David Carr avatar David Carr committed 1745152

plugin: initial import

Comments (0)

Files changed (27)

MongeezGrailsPlugin.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import grails.plugin.mongeez.ReflectionsChangeSetFileProvider
+import org.mongeez.MongeezRunner
+
+class MongeezGrailsPlugin {
+    def version = "0.2.0-SNAPSHOT"
+    def grailsVersion = "2.0 > *"
+    def dependsOn = [:]
+    def loadAfter = ['mongodb']
+    def pluginExcludes = [
+        "grails-app/i18n/messages.properties",
+        'grails-app/migrations/**',
+        "grails-app/views/index.gsp",
+        "src/docs/**"
+    ]
+
+    def title = "Mongeez Plugin"
+    def author = "David M. Carr"
+    def authorEmail = "david@carrclan.us"
+    def description = 'A plugin that integrates the Mongeez change management system for MongoDB into Grails.'
+
+    def documentation = "http://davidmc24.bitbucket.org/grails-mongeez"
+    def license = "APACHE"
+    def issueManagement = [ url: "https://bitbucket.org/davidmc24/grails-mongeez/issues" ]
+    def scm = [ url: "https://bitbucket.org/davidmc24/grails-mongeez" ]
+
+    def doWithSpring = {
+        def mongoBeanName = (
+            application.config?.grails?.mongeez?.mongoBean ?:
+                manager?.hasGrailsPlugin('mongodb') ? 'mongoBean' : 'mongo'
+        )
+        def databaseName = (
+            application.config?.grails?.mongeez?.databaseName ?:
+                application.config?.grails?.mongo?.databaseName ?:
+                    application.config?.mongo?.databaseName ?:
+                        application.metadata.getApplicationName()
+        )
+        def updateOnStart = application.config?.grails?.mongeez?.updateOnStart ?: false
+        changeSetFileProvider(ReflectionsChangeSetFileProvider)
+        mongeez(MongeezRunner) {
+            executeEnabled = updateOnStart
+            mongo = ref(mongoBeanName)
+            dbName = databaseName
+            changeSetFileProvider = ref('changeSetFileProvider')
+        }
+    }
+}

application.properties

+#Grails Metadata file
+#Fri Nov 09 20:11:24 EST 2012
+app.grails.version=2.0.0
+app.name=mongeez
+plugins.rest-client-builder=1.0.2

grails-app/conf/BuildConfig.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+grails.project.source.level = 1.6
+grails.project.target.level = 1.6
+
+grails.project.dependency.resolution = {
+    inherits('global')
+    repositories {
+        grailsCentral()
+        mavenCentral()
+        mavenRepo('https://oss.sonatype.org/content/repositories/snapshots')
+    }
+    dependencies {
+        compile('org.mongeez:mongeez:0.9.2-SNAPSHOT') {
+            excludes('commons-logging')
+        }
+        compile('org.reflections:reflections:0.9.8')
+        compile('org.mongodb:mongo-java-driver:2.9.2')
+    }
+    plugins {
+        build(":tomcat:$grailsVersion",
+              ":release:2.0.4") {
+            export = false
+        }
+    }
+}

grails-app/conf/Config.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// configuration for plugin testing - will not be included in the plugin zip
+grails.doc.title = 'Mongeez Plugin'
+grails.doc.authors = 'David M. Carr'
+grails.doc.license = 'Apache License 2.0'
+grails.doc.copyright = 'Copyright 2012 David M. Carr, Commerce Technologies'

grails-app/conf/spring/resources.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+beans = {
+    mongo(com.mongodb.Mongo) // Default server, default port
+}

grails-app/controllers/grails/mongeez/MongeezController.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package grails.mongeez
+
+import com.mongodb.BasicDBObject
+import com.mongodb.QueryBuilder
+import java.text.SimpleDateFormat
+import org.apache.commons.lang.time.DateFormatUtils
+import org.mongeez.dao.MongeezDao
+import org.mongeez.reader.ChangeSetReaderFactory
+
+class MongeezController {
+    def changeSetFileProvider
+    def mongeez
+    def mongo
+
+    def index() {
+        def pendingChangeSets = getPendingChangeSets()
+        def changeSetExecutions = getChangeSetExecutions()
+        [pendingChangeSets: pendingChangeSets, changeSetExecutions: changeSetExecutions]
+    }
+
+    def pendingChangeSets() {
+        def pendingChangeSets = getPendingChangeSets()
+        render(template: 'pendingChangeSets', model: [pendingChangeSets: pendingChangeSets])
+    }
+
+    def executedChangeSets() {
+        def changeSetExecutions = getChangeSetExecutions()
+        render(template: 'executedChangeSets', model: [changeSetExecutions: changeSetExecutions])
+    }
+
+    def run() {
+        mongeez.execute()
+        flash.message = 'Ran Mongeez'
+        redirect(action: 'index')
+    }
+
+    private def getMongeezCollection() {
+        def dbName = mongeez.getDbName()
+        def db = mongo.getDB(dbName)
+        def dbColl =  db.getCollection('mongeez')
+        return dbColl
+    }
+
+    private def getPendingChangeSets() {
+        // TODO: use mongeez to get this information
+        def pendingChangeSets = []
+        def changeSetReaderFactory = ChangeSetReaderFactory.getInstance()
+        def dao = new MongeezDao(mongo, mongeez.getDbName())
+        def changeSetFiles = changeSetFileProvider.getChangeSetFiles()
+        changeSetFiles.each { changeSetFile ->
+            def changeSetReader = changeSetReaderFactory.getChangeSetReader(changeSetFile)
+            def changeSets = changeSetReader.getChangeSets(changeSetFile)
+            changeSets.each { changeSet ->
+                if(changeSet.isRunAlways() || !dao.wasExecuted(changeSet)) {
+                    pendingChangeSets.add(changeSet)
+                }
+            }
+        }
+        return pendingChangeSets
+    }
+
+    private def getChangeSetExecutions() {
+        // TODO: use mongeez to get this information
+        def dbColl = getMongeezCollection()
+        def query = QueryBuilder.start('type').is('changeSetExecution').get()
+        // TODO: get a single way to determine the true order of existing executions... finer grained date
+        def changeSetExecutions = dbColl.find(query).sort(new BasicDBObject([date: 1, resourcePath: 1])).toArray()
+        def dateFormatter = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT
+        def datePattern = dateFormatter.getPattern()
+        def dateParser = new SimpleDateFormat(datePattern)
+        changeSetExecutions.each { execution ->
+            def origDate = execution.date
+            def newDate = origDate[0..-4] + origDate[-2..-1] // Strip out colon in timezone
+            execution.dateObj = dateParser.parse(newDate)
+        }
+    }
+}

grails-app/migrations/20120131/insert-users.js

+//mongeez formatted javascript
+//changeset bob:insert-users
+db.user.insert({name: 'Atticus'});
+db.user.insert({name: 'Blaine'});
+db.user.insert({name: 'Caelum'});
+db.user.insert({name: 'Damien'});
+db.user.insert({name: 'Elspeth'});
+db.user.insert({name: 'Freya'});
+db.user.insert({name: 'Genesis'});
+db.user.insert({name: 'Hermione'});
+db.user.insert({name: 'Isadora'});
+db.user.insert({name: 'Jared'});
+db.user.insert({name: 'Kyla'});
+db.user.insert({name: 'Lucia'});
+db.user.insert({name: 'Magnus'});
+db.user.insert({name: 'Narcissa'});
+db.user.insert({name: 'Orion'});
+db.user.insert({name: 'Persephone'});
+db.user.insert({name: 'Quinn'});
+db.user.insert({name: 'Reagan'});
+db.user.insert({name: 'Silas'});
+db.user.insert({name: 'Thebe'});
+db.user.insert({name: 'Uston'});
+db.user.insert({name: 'Vada'});
+db.user.insert({name: 'Waylin'});
+db.user.insert({name: 'Xanthie'});
+db.user.insert({name: 'Yvette'});
+db.user.insert({name: 'Zephyr'});

grails-app/migrations/20120227/add-roles.js

+//mongeez formatted javascript
+//changeset jane:add-roles
+db.role.insert({name: 'user'});
+db.role.insert({name: 'admin'});

grails-app/migrations/20120227/update-users.js

+//mongeez formatted javascript
+
+//changeset bob:rename-name-to-firstName
+db.user.update({name: {$exists: true}}, {$rename: {name: 'firstName'}}, false, true);
+
+//changeset bob:add-user-last-name
+db.user.update({firstName: 'Atticus'}, {$set: {lastName: 'Hyperion'}});
+db.user.update({firstName: 'Blaine'}, {$set: {lastName: 'Zachariah'}});
+db.user.update({firstName: 'Caelum'}, {$set: {lastName: 'Draco'}});
+db.user.update({firstName: 'Damien'}, {$set: {lastName: 'Nilo'}});
+db.user.update({firstName: 'Elspeth'}, {$set: {lastName: 'Rosalind'}});
+db.user.update({firstName: 'Freya'}, {$set: {lastName: 'Eloise'}});
+db.user.update({firstName: 'Genesis'}, {$set: {lastName: 'Alexander'}});
+db.user.update({firstName: 'Hermione'}, {$set: {lastName: 'Octavia'}});
+db.user.update({firstName: 'Isadora'}, {$set: {lastName: 'Fate'}});
+db.user.update({firstName: 'Jared'}, {$set: {lastName: 'Saul'}});
+db.user.update({firstName: 'Kyla'}, {$set: {lastName: 'Fallon'}});
+db.user.update({firstName: 'Lucia'}, {$set: {lastName: 'Nemesis'}});
+db.user.update({firstName: 'Magnus'}, {$set: {lastName: 'Ishmael'}});
+db.user.update({firstName: 'Narcissa'}, {$set: {lastName: 'Amethyst'}});
+db.user.update({firstName: 'Orion'}, {$set: {lastName: 'Severus'}});
+db.user.update({firstName: 'Persephone'}, {$set: {lastName: 'Hera'}});
+db.user.update({firstName: 'Quinn'}, {$set: {lastName: 'Helaina'}});
+db.user.update({firstName: 'Reagan'}, {$set: {lastName: 'Hestia-Faye'}});
+db.user.update({firstName: 'Silas'}, {$set: {lastName: 'Finn'}});
+db.user.update({firstName: 'Thebe'}, {$set: {lastName: 'Rosalie'}});
+db.user.update({firstName: 'Uston'}, {$set: {lastName: 'Sterling'}});
+db.user.update({firstName: 'Vada'}, {$set: {lastName: 'Theodora'}});
+db.user.update({firstName: 'Waylin'}, {$set: {lastName: 'Thesus'}});
+db.user.update({firstName: 'Xanthie'}, {$set: {lastName: 'Althea'}});
+db.user.update({firstName: 'Yvette'}, {$set: {lastName: 'Irelynd'}});
+db.user.update({firstName: 'Zephyr'}, {$set: {lastName: 'Indigo'}});
+
+//changeset jane:apply-roles
+var userId = db.role.findOne({name: 'user'})._id;
+var adminId = db.role.findOne({name: 'admin'})._id;
+db.user.update({}, {$set: {roles: [userId]}}, false, true);
+db.user.update({firstName: {$in: ['Freya', 'Persephone']}}, {$addToSet: {roles: adminId}}, false, true);

grails-app/migrations/20120315/add-user-active-field.js

+//mongeez formatted javascript
+
+//changeset frank:all-existing-users-active
+db.user.update({}, {$set: {active: true}}, false, true);
+
+//changeset frank:ensure-user-active-always-exists runAlways:true
+db.user.update({active: {$exists: false}}, {$set: {active: false}}, false, true);

grails-app/views/index.gsp

+<%--
+  - Copyright 2012 David M. Carr, Commerce Technologies
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -   http://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  --%>
+<%@ page contentType="text/html;charset=UTF-8" %>
+<html>
+<head>
+    <title>Mongeez Test App</title>
+</head>
+<body>
+    <p>Welcome to the Mongeez Test App.</p>
+
+    <p>Links:</p>
+    <ul>
+        <li><g:link controller="mongeez" action="index">Mongeez Index</g:link></li>
+        <li><g:link controller="mongeez" action="pendingChangeSets">Mongeez Pending ChangeSets</g:link></li>
+        <li><g:link controller="mongeez" action="executedChangeSets">Mongeez Executed ChangeSets</g:link></li>
+    </ul>
+</body>
+</html>

grails-app/views/mongeez/_executedChangeSets.gsp

+<%--
+  - Copyright 2012 David M. Carr, Commerce Technologies
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -   http://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  --%>
+<%@ page contentType="text/html;charset=UTF-8" %>
+<html>
+<head>
+    <title>Mongeez Executed Change Sets</title>
+</head>
+<body>
+    <div class="mongeezChangeSetsExecuted">
+        <g:if test="${changeSetExecutions}">
+            <table class="mongeezChangeSetsExecutedTable">
+                <thead>
+                    <tr>
+                        <th class="column date">Date</th>
+                        <th class="column resourcePath">Resource Path</th>
+                        <th class="column author">Author</th>
+                        <th class="column changeId">Change ID</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <g:each in="${changeSetExecutions}" var="changeSetExecution">
+                        <tr>
+                            <td class="column date">
+                                <g:formatDate date="${changeSetExecution.dateObj}" type="datetime" style="SHORT"/>
+                            </td>
+                            <td class="column resourcePath">${changeSetExecution.resourcePath}</td>
+                            <td class="column author">${changeSetExecution.author}</td>
+                            <td class="column changeId">${changeSetExecution.changeId}</td>
+                        </tr>
+                    </g:each>
+                </tbody>
+            </table>
+        </g:if>
+        <g:else>
+            <div class="mongeezNoChangeSetsExecuted">Mongeez hasn't executed any change sets yet.</div>
+        </g:else>
+    </div>
+</body>
+</html>

grails-app/views/mongeez/_pendingChangeSets.gsp

+<%--
+  - Copyright 2012 David M. Carr, Commerce Technologies
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -   http://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  --%>
+<%@ page contentType="text/html;charset=UTF-8" %>
+<html>
+<head>
+    <title>Mongeez Pending Change Sets</title>
+</head>
+<body>
+    <div class="mongeezChangeSetsPending">
+        <g:if test="${pendingChangeSets}">
+            <table class="mongeezChangeSetsPendingTable">
+                <thead>
+                    <tr>
+                        <th class="column resourcePath">Resource Path</th>
+                        <th class="column author">Author</th>
+                        <th class="column changeId">Change ID</th>
+                        <th class="column runAlways">Run Always</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <g:each in="${pendingChangeSets}" var="pendingChangeSet">
+                        <tr>
+                            <td class="column resourcePath">${pendingChangeSet.resourcePath}</td>
+                            <td class="column author">${pendingChangeSet.author}</td>
+                            <td class="column changeId">${pendingChangeSet.changeId}</td>
+                            <td class="column runAlways">${pendingChangeSet.runAlways ? 'Yes' : 'No'}</td>
+                        </tr>
+                    </g:each>
+                </tbody>
+            </table>
+        </g:if>
+        <g:else>
+            <div class="mongeezNoChangeSetsPending">Mongeez has executed all available change sets.</div>
+        </g:else>
+    </div>
+</body>
+</html>

grails-app/views/mongeez/index.gsp

+<%--
+  - Copyright 2012 David M. Carr, Commerce Technologies
+  -
+  - Licensed under the Apache License, Version 2.0 (the "License");
+  - you may not use this file except in compliance with the License.
+  - You may obtain a copy of the License at
+  -
+  -   http://www.apache.org/licenses/LICENSE-2.0
+  -
+  - Unless required by applicable law or agreed to in writing, software
+  - distributed under the License is distributed on an "AS IS" BASIS,
+  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  - See the License for the specific language governing permissions and
+  - limitations under the License.
+  --%>
+<%@ page contentType="text/html;charset=UTF-8" %>
+<html>
+<head>
+    <title>Mongeez Status</title>
+    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
+</head>
+<body>
+    <div class="mongeezStatus">
+        <g:if test="${flash.message}">
+            <div class="globalMessage">${flash.message}</div>
+        </g:if>
+
+        <g:if test="${pendingChangeSets}">
+            <g:form action="run" class="mongeezRunUpdateForm">
+                <g:submitButton name="Run Mongeez" class="mongeezRunUpdateButton"/>
+            </g:form>
+        </g:if>
+
+        <g:render template="pendingChangeSets" model="[pendingChangeSets: pendingChangeSets]"/>
+
+        <g:render template="executedChangeSets" model="[changeSetExecutions: changeSetExecutions]"/>
+    </div>
+</body>
+</html>

scripts/MongeezUpdate.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+includeTargets << grailsScript("_GrailsBootstrap")
+
+target(main: "Run mongeez to bring the database up-to-date") {
+    depends(configureProxy, packageApp, classpath, loadApp, configureApp)
+    def mongeez = appCtx.getBean('mongeez')
+    def dbName = mongeez.dbName
+    if (!mongeez.executeEnabled) {
+        mongeez.execute()
+    }
+    event("StatusFinal", ["Mongeez processed database " + dbName + "."])
+}
+
+setDefaultTarget(main)

scripts/_Events.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+eventPackagingEnd = {
+    def srcPath = config.grails?.mongeez?.changelogLocation ?: 'grails-app/migrations'
+    def src = new File(buildSettings.baseDir, srcPath)
+    def target = new File(buildSettings.resourcesDir, 'migrations')
+    if (src.exists()) {
+        ant.sync(toDir: target, overwrite: true) {
+            fileset(dir: src, includes: "**/*.xml,**/*.js")
+        }
+    }
+}

scripts/_Install.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+def srcPath = config.grails?.mongeez?.changelogLocation ?: 'grails-app/migrations'
+def src = new File(buildSettings.baseDir, srcPath)
+ant.mkdir(dir: src)

src/docs/guide/configuration.gdoc

+There are a few configuration properties available.  Most can be left with the default setting.  In particular, if you
+use the [MongoDB GORM|http://grails.org/plugin/mongodb] plugin, you shouldn't need to set either the mongoBean or
+databaseName properties.
+
+{table}
+*Property* | *Default* | *Meaning*
+grails.mongeez.changelogLocation | @grails-app/migrations@ | the folder containing the changelog files (either .js or .xml); directories are supported
+grails.mongeez.updateOnStart | @false@ | if @true@ then an update will be performed on application startup
+grails.mongeez.mongoBean | @mongoBean@/ @mongo@ | the Spring bean name of the Mongo  database connection to use; defaults to @mongoBean@ if the [MongoDB GORM|http://grails.org/plugin/mongodb] plugin is installed, @mongo@ otherwise
+grails.mongeez.databaseName | _application name_/ see notes | the name of the database to use; also checks grails.mongo.databaseName (as used by the [MongoDB GORM|http://grails.org/plugin/mongodb] plugin) and mongo.databaseName, falling back to the name of the application if none of the three properties are present
+{table}

src/docs/guide/generalUsage.gdoc

+h4. Autorun on start
+
+Since Mongeez maintains a record of which changesets have been applied, you can avoid manually updating the database by
+taking advantage of the plugin's auto-run feature. By default this is disabled, but you can enable it by adding a
+setting to to Config.groovy:
+
+{code}
+grails.mongeez.updateOnStart = true
+{code}
+
+This is more commonly used for development and QA environments than in production.

src/docs/guide/gettingStarted.gdoc

+h4. First, install the plugin by adding a dependency in @BuildConfig.groovy@ (replace VERSION with the desired version:
+
+{code}
+plugins {
+   ...
+   runtime ':mongeez:VERSION'
+}
+{code}
+
+or install with @install-plugin@:
+
+{code}
+grails install-plugin mongeez
+{code}
+
+h4. Changelog Creation
+
+Next, you'll need to create some changelogs.  Currently two formats are supported; JavaScript or XML.  The Javascript
+format is recommended, as it's closer to writing plain MongoDB migration scripts.  Documentation of the XML format can
+be found [here|https://github.com/secondmarket/mongeez/wiki/How-to-use-mongeez].  By default, changelog files go in
+@grails-app/migrations@.
+
+When using the JavaScript format, start each file with a comment "//mongeez formatted javascript".  Then add one or more
+changeset sections, with a "//changeset AUTHOR:ID" comment at the start of each changeset.  Replace AUTHOR with some
+way to identify the creator of the changeset and replace ID with an identifier for the changeset.  If you want a
+changeset to be run every update (rather than only once), include "runAlways:true" in the changeset comment.
+
+For example:
+{code}
+//mongeez formatted javascript
+//changeset bob:1
+db.TestCollection.insert({"someField1": "firstChangeSetData"});
+//changeset bob:2
+db.TestCollection.update({}, {$set: {"someField2": "secondChangeSetData"}}, false, true);
+//changeset alice:3 runAlways:true
+db.TestCollection.update({"someField1": {$exists: 1}}, {$set: {"someField1": "thirdChangeSetData"}}, false, true);
+{code}
+
+Some people like to use sequential integers as the IDs for theier changesets within a file.  Others prefer a descriptive
+string.  Either is fine; all that matters is that the combination of the author, ID, and file path uniquely identifies
+the changeset.  It isn't truly mandatory to track the author; if desired, you can use a placeholder value like
+"UNASCRIBED"; just be aware that there's more potential for ID conflict in this case.
+
+Once you have some changesets, you can run the [mongeez-update|Update Scripts] script to update the database
+{code}
+grails mongeez-update
+{code}

src/docs/guide/introduction.gdoc

+The Mongeez plugin helps you manage changes to your [MongoDB|http://www.mongodb.org/] database while developing Grails
+applications.  It does so by leveraging the [Mongeez|https://github.com/secondmarket/mongeez] library.
+
+Mongeez facilitates structure to the process of applying migrations to a database.  You create a set of changelog files
+(each of which contains one or more changesets identified by an author and an ID), optionally organized in directories.
+When Mongeez updates your database, it keeps track of which changesets have already been run on the database, and won't
+re-run them again unless you've specifically told it to.
+
+Users used to using Mongeez directly may notice that this plugin doesn't mention a "mongeez.xml" file that lists
+changelog files.  That's because the plugin doesn't use one.  Instead, the change log files are automatically detected
+and ran in order by name (taking both directory and file name into account).

src/docs/guide/releaseNotes.gdoc

+Below is the history of Mongeez plugin releases.
+
+h4. 0.2.0 (TBD)
+* First public release
+
+h4. 0.1.2 (September 12, 2012)
+* Private release
+
+h4. 0.1.1 (July 2, 2012)
+* Private release

src/docs/guide/toc.yml

+introduction:
+  title: Introduction
+  releaseNotes: Release Notes
+gettingStarted: Getting Started
+configuration: Configuration
+generalUsage: General Usage

src/docs/ref/Update Scripts/mongeez-update.gdoc

+h1. mongeez-update
+
+h2. Purpose
+
+Updates a database to the current version.
+
+h2. Description
+
+Runs all un-run change sets. Executes against the configured database for the current environment (defaults to @dev@).
+
+Usage:
+{code}
+grails [environment] mongeez-update
+{code}
+
+Arguments: _none_.

src/groovy/grails/plugin/mongeez/ReflectionsChangeSetFileProvider.groovy

+/*
+ * Copyright 2012 David M. Carr, Commerce Technologies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package grails.plugin.mongeez
+
+import org.mongeez.reader.ChangeSetFileProvider
+import org.springframework.core.io.Resource
+import org.reflections.Reflections
+import org.reflections.scanners.ResourcesScanner
+import java.util.regex.Pattern
+import org.springframework.core.io.ClassPathResource
+
+class ReflectionsChangeSetFileProvider implements ChangeSetFileProvider {
+    List<Resource> getChangeSetFiles() {
+        // TODO Consider using pre-scanned metadata, at least when packaged as a war
+        Reflections reflections = new Reflections('migrations', new ResourcesScanner())
+        def migrationResourcePaths = reflections.getResources(Pattern.compile('.*(\\.js|\\.xml)'))
+        def migrationResources = migrationResourcePaths.sort().collect{new ClassPathResource(it)}
+        return migrationResources
+    }
+}

web-app/WEB-INF/applicationContext.xml

+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+	<bean id="grailsApplication" class="org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean">
+		<description>Grails application factory bean</description>
+		<property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
+		<property name="grailsResourceLoader" ref="grailsResourceLoader" />
+	</bean>
+
+	<bean id="pluginManager" class="org.codehaus.groovy.grails.plugins.GrailsPluginManagerFactoryBean">
+		<description>A bean that manages Grails plugins</description>
+		<property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
+		<property name="application" ref="grailsApplication" />
+	</bean>
+
+	<bean id="grailsConfigurator" class="org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator">
+		<constructor-arg>
+			<ref bean="grailsApplication" />
+		</constructor-arg>
+		<property name="pluginManager" ref="pluginManager" />
+	</bean>
+
+	<bean id="grailsResourceLoader" class="org.codehaus.groovy.grails.commons.GrailsResourceLoaderFactoryBean" />
+
+	<bean id="characterEncodingFilter" class="org.springframework.web.filter.CharacterEncodingFilter">
+		<property name="encoding">
+			<value>utf-8</value>
+		</property>
+	</bean>
+</beans>

web-app/WEB-INF/sitemesh.xml

+<sitemesh>
+    <page-parsers>
+        <parser content-type="text/html"
+            class="org.codehaus.groovy.grails.web.sitemesh.GrailsHTMLPageParser" />
+        <parser content-type="text/html;charset=ISO-8859-1"
+            class="org.codehaus.groovy.grails.web.sitemesh.GrailsHTMLPageParser" />
+        <parser content-type="text/html;charset=UTF-8"
+            class="org.codehaus.groovy.grails.web.sitemesh.GrailsHTMLPageParser" />
+    </page-parsers>
+
+    <decorator-mappers>
+        <mapper class="org.codehaus.groovy.grails.web.sitemesh.GrailsLayoutDecoratorMapper" />
+    </decorator-mappers>
+</sitemesh>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.