From c7c17ee4112c2520ee4dee2bc50143cab9a7d743 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=B6ne?= <rene.schoene@tu-dresden.de>
Date: Tue, 14 Apr 2020 14:07:07 +0000
Subject: [PATCH] Versioning works now after testing in proof-of-concept repo.

---
 .gitignore                                    |  2 +
 .gitlab-ci.yml                                | 41 ++++++++++-
 CONTRIBUTING.md                               | 43 ++++++++---
 build.gradle                                  | 71 ++++++++++---------
 .../org/jastadd/relast/compiler/Compiler.java |  9 ++-
 src/main/resources/.gitignore                 |  1 -
 src/main/resources/RelASTVersion.properties   |  2 +
 7 files changed, 120 insertions(+), 49 deletions(-)
 delete mode 100644 src/main/resources/.gitignore
 create mode 100644 src/main/resources/RelASTVersion.properties

diff --git a/.gitignore b/.gitignore
index 552ea58..7be691a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 *.jar
+!gradle/wrapper/gradle-wrapper.jar
 .project
 .classpath
 .idea/
@@ -12,3 +13,4 @@ src/test/jastadd/*/*.ast
 src/test/jastadd/*/*.jadd
 src/test/jastadd/*/*ResolverStubs.jrag
 !src/test/jastadd/*/MyRefResolver.jadd
+/gradle.properties
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9729a31..b6bf485 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,43 @@
 stages:
-  - build
+- build
+- test
+- jar
 
-test:
+build:
   image: openjdk:8
   stage: build
   script:
-    - ./gradlew --no-daemon build
+    - ./gradlew --console=plain --build-cache assemble
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: push
+    paths:
+      - build
+      - .gradle
+
+test:
+  image: openjdk:8
+  stage: test
+  script:
+    - ./gradlew --continue --console=plain --info check
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: pull
+    paths:
+      - build
+      - .gradle
+
+jar:
+  image: openjdk:8
+  stage: jar
+  script:
+    - ./gradlew --continue --console=plain --info jar
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: pull
+    paths:
+      - build
+      - .gradle
+  artifacts:
+    paths:
+      - "/builds/jastadd/*/build/libs/*relast*.jar"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1d6c4f3..4699763 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,7 +2,7 @@
 
 To propose a new feature, or to report a bug, first [create an issue][create-issue] and add labels accordingly.
 Working on such issues is done by creating a merge request from the issue page, which 1) creates a new branch to work on, and 2) creates a new WIP merge request for the new branch.
-Once done (and new tests are written to ensure, a bug is really fixed, and the feature does the right thing), the merge request will be accepted and merged into `master`.
+Once done (and new tests are written to ensure, a bug is really fixed, and the feature does the right thing), the merge request will be accepted and merged into `develop`.
 
 # Creating normal test cases
 
@@ -63,7 +63,7 @@ Aside from the [normal tests](#creating-normal-test-cases), there are some speci
 
 ## Negative parser tests
 
-To check, errors are found and contain the correct messages, one test [`Errors`](/../blob/master/src/test/java/org/jastadd/relast/tests/Errors.java) is used.
+To check, errors are found and contain the correct messages, one test [`Errors`][Errors.java] is used.
 Here, the RelAST compiler is invoked manually, and the actual error messages are compared to expected ones for each grammar in `src/test/jastadd/errors`.
 The expected messages can contain the special word `$FILENAME` to refer to the filename of the grammar, if there is only one, or `$FILENAME1`, `$FILENAME2` etc., if there are many.
 Furthermore, empty lines, lines starting with `//` and the order of the error messages are ignored.
@@ -74,12 +74,35 @@ Currently, there is one test to test whether the output of RelAST is a valid inp
 To achieve this, there are two Gradle tasks. The first produces the usual `.ast` and `.jadd` files, whereas the second task takes the `.ast` as input.
 The test then ensures, that both output grammars are identical.
 
-# Publishing
-
-To publish a new version, the following needs to be done:
-
-1) Create a new annotated tag with an appropriate version number increase (major, minor, patch) described in [semantic versioning](https://semver.org/)
-2) If not already present, create a new file `gradle.properties` with two entries `repoUser` and `repoPassword` for our Nexus repository.
-3) Run `./gradlew publish -PwithNewVersion` (maybe also adding ` -PasSnapshot` to create a SNAPSHOT release)
-
+# Releases and Publishing (Maintainer only)
+
+Important information:
+
+- Currently, we are publishing to a private Nexus Maven repository only.
+- We are using [git-flow][git-flow], so only new merge requests are considered for releases to appear in the `master` branch.
+- The version is set in the configuration file [RelASTVersion.properties][RelASTVersion.properties].
+
+The workflow:
+
+1) Finish your work with the current feature(s) and merge those back in `develop`.
+1) Choose a new version number `$nextVersion` depending on the introduced changes **following [semantic versioning][semantic-versioning]**.
+1) Create a new release branch named `release/$nextVersion` and switch to this branch.
+1) Set the version number in the config file calling `./gradlew newVersion -Pvalue=$nextVersion`
+1) Commit this change.
+1) (Optional) Build a new jar file calling `./gradlew jar` (this is automatically called in the publish step and only used to test the newly set version number)
+1) Check, if everything works as planned, e.g., version number is picked up when running the application with `--version`, and all test succeed.
+1) Merge the release branch into `master` (using a merge request) and also back into `develop`.
+1) Delete the release branch.
+1) [Create a new release][create-release]. Choose the following:
+    - *Tag name*: the chosen version number
+    - *Create from*: leave the default `master`
+    - *Message*: "Version " and the chose version number
+    - *Release notes*: list the (important) changes compared to the last release, prepend a link to the built jar using the line `[:floppy_disk: publish-relast-poc-$nextVersion.jar](/../../../-/jobs/$jobNumber/artifacts/raw/build/libs/publish-relast-poc-$nextVersion.jar?inline=false)` replacing `$jobNumber` with the `jar` job of the pipeline run after the merge request, and `$nextVersion`
+1) Publish the built jar to the maven repository calling `./gradlew publish`
+
+[git-flow]: https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow
+[Errors.java]: /../blob/master/src/test/java/org/jastadd/relast/tests/Errors.java
+[RelASTVersion.properties]: /../-/blob/master/src/main/resources/RelASTVersion.properties
+[semantic-versioning]: https://semver.org/
+[create-release]: /../-/tags/new
 [create-issue]: https://git-st.inf.tu-dresden.de/jastadd/relational-rags/issues/new
diff --git a/build.gradle b/build.gradle
index 2ed112d..aa950e4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,6 +14,9 @@ repositories {
     jcenter()
 }
 
+group = 'org.jastadd'
+apply plugin: 'maven-publish'
+
 buildscript {
     repositories.jcenter()
     dependencies {
@@ -43,6 +46,25 @@ sourceSets {
     }
 }
 
+def versionFile = 'src/main/resources/RelASTVersion.properties'
+def oldProps = new Properties()
+
+try {
+    file(versionFile).withInputStream { stream -> oldProps.load(stream) }
+    version = oldProps['version']
+} catch (e) {
+    // this happens, if either the properties file is not present, or cannot be read from
+    throw new GradleException("File ${versionFile} not found or unreadable. Aborting.")
+}
+
+task newVersion() {
+    doFirst {
+        def props = new Properties()
+        props['version'] = value
+        props.store(file(versionFile).newWriter(), null)
+    }
+}
+
 jar {
     manifest {
         attributes "Main-Class": 'org.jastadd.relast.compiler.Compiler'
@@ -110,46 +132,27 @@ jastadd {
     jastaddOptions = ["--lineColumnNumbers", "--safeLazy", "--visitCheck=true", "--rewrite=cnta", "--cache=all"]
 }
 
-def versionFile = 'src/main/resources/RelASTVersion.properties'
-task updateVersion {
-    /* version string handling adapted from https://bitbucket.org/extendj/extendj/src/master/build.gradle
-       written by Jesper Öqvist <jesper.oqvist@cs.lth.se> */
-    group 'build'
-    description 'Updates the version file for RelAST'
-
-    doLast {
-        def oldProps = new Properties()
-        String oldFullVersion, fullVersion
-
-        try {
-            file(versionFile).withInputStream { stream -> oldProps.load(stream) }
-            oldFullVersion = oldProps['version']
-        } catch (ignored) {
-            oldFullVersion = "???"
+publishing {
+    publications {
+        maven(MavenPublication) {
+            artifact("build/libs/relast-${version}.jar") {
+                extension 'jar'
+            }
         }
-        try {
-            def proc = 'git describe'.execute(null, rootDir)
-            if  (proc.waitFor() == 0) {
-                fullVersion = proc.text.trim()
-                if (hasProperty('withNewVersion')) {
-                    // Trim to get latest tag:
-                    version = (fullVersion =~ /-\d+\-g.+$/).replaceAll('')
-                }
-                if (oldFullVersion != fullVersion) {
-                    def props = new Properties()
-                    props['version'] = fullVersion
-                    props.store(file(versionFile).newWriter(), null)
-                }
-            } else {
-                logger.warn('No git tags found.')
+    }
+    repositories {
+        maven {
+            name 'nexus'
+            url "http://172.22.1.152:8081/repository/" + (project.hasProperty('asSnapshot') ? "maven-snapshots" : "maven-releases/")
+            credentials {
+                username project.ext.properties.repoUser
+                password project.ext.properties.repoPassword
             }
-        } catch (IOException e) {
-            logger.warn("Failded to run git describe (${e.getMessage()}).")
         }
     }
 }
 
-processResources.dependsOn updateVersion
+publish.dependsOn jar
 
 task firstRelationsRun(type: RelastTest) {
     relastFiles 'src/test/jastadd/relations/Relations.relast'
diff --git a/src/main/java/org/jastadd/relast/compiler/Compiler.java b/src/main/java/org/jastadd/relast/compiler/Compiler.java
index 2f6ef25..dfa3d1a 100644
--- a/src/main/java/org/jastadd/relast/compiler/Compiler.java
+++ b/src/main/java/org/jastadd/relast/compiler/Compiler.java
@@ -23,6 +23,7 @@ public class Compiler {
   private FlagOption optionResolverHelper;
   private FlagOption optionUseJastaddNames;
   private FlagOption optionQuiet;
+  private FlagOption optionVersion;
   private CommandLine commandLine;
 
   public Compiler(String[] args) throws CommandLineException {
@@ -32,6 +33,11 @@ public class Compiler {
     commandLine = new CommandLine(options);
     commandLine.parse(args);
 
+    if (optionVersion.isSet()) {
+      System.out.println(readVersion());
+      return;
+    }
+
     printMessage("Running RelAST " + readVersion());
 
     if (commandLine.getArguments().size() < 1) {
@@ -136,7 +142,7 @@ public class Compiler {
    */
   private String readVersion() {
     try {
-      ResourceBundle resources = ResourceBundle.getBundle("Version");
+      ResourceBundle resources = ResourceBundle.getBundle("RelASTVersion");
       return resources.getString("version");
     } catch (MissingResourceException e) {
       return "version ?";
@@ -179,6 +185,7 @@ public class Compiler {
     optionUseJastaddNames = addOption(new FlagOption("useJastAddNames", "generate names in the form of addX, removeX and setX. If omitted, the default, original naming scheme resulting in addToX, removeFromX and setX will be used."));
     optionSerializer = addOption(new EnumOption("serializer", "generate a (de-)serializer", Arrays.asList("jackson", "jackson-json-pointer", "jackson-manual-references"), "jackson"));
     optionQuiet = addOption(new FlagOption("quiet", "do not output anything on stdout"));
+    optionVersion = addOption(new FlagOption("version", "print version and exit"));
   }
 
   private <OptionType extends Option<?>> OptionType addOption(OptionType option) {
diff --git a/src/main/resources/.gitignore b/src/main/resources/.gitignore
deleted file mode 100644
index e4a21f4..0000000
--- a/src/main/resources/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-RelASTVersion.properties
diff --git a/src/main/resources/RelASTVersion.properties b/src/main/resources/RelASTVersion.properties
new file mode 100644
index 0000000..303d396
--- /dev/null
+++ b/src/main/resources/RelASTVersion.properties
@@ -0,0 +1,2 @@
+#Thu Jan 16 09:42:49 CET 2020
+version=0.2.4-28-g22c4762
-- 
GitLab