http://git.e-strix.com/sample_fx_app.git/

W każdym (nawet freelancer’skim) projekcie przychodzi moment na to aby zacząć pisać kod i tu już dostajemy wiatr w żagiel i stopy wody pod kilem. W zasadzie ogranicza nas tylko lenistwo z jednej strony i kreatywność z drugiej.

Dla potrzeb prezentacji wybiorę sobie coś na czasie, a będzie to:

  • spring-boot
  • gradle
  • git
  • javafx

A zatem bez zbędnych patosów, teorii i literatury zacznijmy od stworzenia kilku plików.

Tworzenie projektu

Zacznijmy od utworzenia repozytorium. Jeśli nie widziałeś mojego wpisu na ten temat to zobacz pierw: php7-git-gitlist.

A teraz do rzeczy. Struktura projektu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
└───javafx-git-sample<br>
    │     .gitignore<br>
    │     build.gradle<br>
    │     latest.properties<br>
    │     settings.gradle<br>
    │<br>
    ├───gradle<br>
    │        release.gradle<br>
    │<br>
    └───src<br>
        └───main<br>
            ├───java<br>
            │    └───pl<br>
            │        └───estrix<br>
            │            └───javafx<br>
            │                    FilterProp.java<br>
            │                    JavaApplication.java<br>
            │                    MainController.java<br>
            │<br>
            └───resources<br>
                │     logo.png<br>
                │     main.fxml<br>
                │<br>
                └───META-INF<br>
                        spring.factories

Plik .gitignore
1
2
3
4
.gradle/<br>
.idea/<br>
build/<br>
*.iml

Plik build.gradle
1
2
3
4
5
6
7
8
9
buildscript {<br>
    repositories {<br>
        mavenCentral()<br>
        jcenter()<br>
    }<br>
    dependencies {<br>
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE")<br>
    }<br>
}

apply from: ‚gradle/release.gradle’
apply plugin: ‚java’
apply plugin: ‚org.springframework.boot’
apply plugin: ‚io.spring.dependency-management’

bootJar {
mainClassName = ‚pl.estrix.javafx.JavaApplication’
manifest {
attributes ‚Start-Class’: ‚pl.estrix.javafx.JavaApplication’
}
}

springBoot {
mainClassName = ‚pl.estrix.javafx.JavaApplication’
}

repositories {
mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
compile(„org.springframework.boot:spring-boot-starter”)
testCompile(„junit:junit”)
}

def buildTime() {
new Date().format(‚yyyy.MM.dd HH:mm’)
}

def generatedResources = „$buildDir/resources/main/”
sourceSets {
main {
output.dir(generatedResources, builtBy: ‚generateMyResources’)
}
}

task generateMyResources {
doLast {
def generatedTmp = new File(generatedResources)
if( !generatedTmp.exists() ) {
generatedTmp.mkdirs()
}
def generated = new File(generatedResources, „filter.properties”)

1
2
3
4
5
        generated.text = "estrix.application.biuld-time=${buildTime()}\n" +<br>
                "estrix.application.name=${project.name}\n" +<br>
                "estrix.application.version=${project.version}\n"<br>
    }<br>
}

Plik latest.properties
1
2
3
4
#Tue Apr 10 16:59:22 CEST 2018<br>
bugfix=0<br>
major=1<br>
minor=0

Plik settings.gradle
1
rootProject.name = 'JavaFxGitSample'

Plik gradle/release.gradle

Notatka: Pomysł na zarządzanie wersjami pochodzi z https://www.youtube.com/watch?v=Y6SVoXFsw7I

1
2
3
4
5
class Version {<br>
    int major<br>
    int minor<br>
    int bugfix<br>
    boolean snapshot = true

static Version load(File versionFile){
def props = new Properties()
versionFile.withInputStream {
stream -> props.load(stream)
}
def major = Integer.parseInt(props[‚major’])
def minor = Integer.parseInt(props[‚minor’])
def bugfix = Integer.parseInt(props[‚bugfix’])
return new Version(major:major, minor:minor, bugfix:bugfix)
}

String toString(){
„${major}.${minor}.${bugfix}${snapshot ? ‚-SNAPSHOT’:”}”
}

void store(File versionFile){
def props = new Properties()
props[‚bugfix’] = bugfix.toString()
props[‚major’] = major.toString()
props[‚minor’] = minor.toString()
props.store(versionFile.newWriter(), null)
}

Version next(String releaseType = „bugfix”){
if(releaseType == „major”){
return new Version(major:major+1, minor:0, bugfix:0)
}else if(releaseType == „minor”){
return new Version(major:major, minor:minor+1, bugfix:0)
}else{
return new Version(major:major, minor:minor, bugfix:bugfix+1)
}
}
}

def latest = Version.load(rootProject.file(„latest.properties”))
allprojects{
version = latest.next()
}
gradle.taskGraph.whenReady { graph ->
if(graph.hasTask(„:release”)){
allprojects{
version = latest.next(release.type)
version.snapshot = false
}
}
}

task persistVersionInfo(type:Exec){
commandLine „git” , „commit”,”-i”, „latest.properties”, „-m”, „‚ update version to ${-> version }'”
doFirst{
version.store(file(„latest.properties”))
}
}

task tagWorkspace(type:Exec){
commandLine ‚git’, ‚tag’, „${-> version }”
commandLine ‚git’, ‚push’, ‚origin’, ‚HEAD:master’
}

task release(type:Release){
type = System.getProperty(„type”)
dependsOn „build”, „persistVersionInfo”, „tagWorkspace”
}

import org.gradle.api.internal.tasks.options.Option

class Release extends DefaultTask{
@Option(option=”type”, description=”the type of a release.”)
String type = „bugfix”

1
2
3
4
    @TaskAction void release(){<br>
        println "doing a $type release of ${project.version}"<br>
    }<br>
}

Plik src/main/java/pl/estrix/javafx/FilterProp.java
1
package pl.estrix.javafx;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(„filter.properties”)
public class FilterProp {

@Value(„${estrix.application.name}”)
private String name;
@Value(„${estrix.application.version}”)
private String version;
@Value(„${estrix.application.biuld-time}”)
private String biuldTime;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getVersion() {
return version;
}

public void setVersion(String version) {
this.version = version;
}

public String getBiuldTime() {
return biuldTime;
}

1
2
3
4
    public void setBiuldTime(String biuldTime) {<br>
        this.biuldTime = biuldTime;<br>
    }<br>
}<br>

Plik src/main/java/pl/estrix/javafx/JavaApplication.java
1
package pl.estrix.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@SpringBootApplication
@ComponentScan(„pl.estrix.javafx”)
@PropertySource(„classpath:filter.properties”)
@Configuration
public class JavaApplication extends Application {

private ConfigurableApplicationContext context;
private Parent rootNode;

public static void main(final String[] args) {
Application.launch(args);
}

@Override
public void init() throws Exception {
SpringApplicationBuilder builder = new SpringApplicationBuilder(JavaApplication.class);
context = builder.run(getParameters().getRaw().toArray(new String[0]));

FXMLLoader loader = new FXMLLoader(getClass().getResource(„/main.fxml”));
loader.setControllerFactory(context::getBean);
rootNode = loader.load();

}

@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(rootNode, 480, 320));
primaryStage.centerOnScreen();
primaryStage.show();
}

@Override
public void stop() throws Exception {
context.close();
}

1
}

Plik src/main/java/pl/estrix/javafx/MainController.java
1
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MainController {

@Autowired
private FilterProp filterProp;

@FXML
private Label propName;
@FXML
private Label propVersion;
@FXML
private Label propBuildTime;

1
2
3
4
5
6
7
    @FXML<br>
    public void initialize() {<br>
        propName.setText(filterProp.getName());<br>
        propVersion.setText(filterProp.getVersion());<br>
        propBuildTime.setText(filterProp.getBiuldTime());<br>
    }<br>
}

Plik src/main/resources/main.fxml


Plik src/main/resources/META-INF/spring.factories

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\<br>
pl.estrix.javafx.JavaApplication

Plik src/main/resources/logo.png
1
wget http://e-strix.com/wp-content/uploads/2018/04/logo.png -P src/main/resources/

Budowa lokalna

Uruchamianie

1
gradle clean generateMyResources bootRun

Budowanie jar
1
gradle clean generateMyResources bootJar

Uruchamianie
1
java -jar build\libs\JavaFxGitSample-1.0.1-SNAPSHOT.jar

No dobra, teraz wiemy jak zbudować aplikację. Ale docelowo ma to robić Ci, zatem zabieramy się za konfigurację job’ów.

Konfiguracja Jenkins

Budowa zdalna

Jenkins new project

W polu: Repository URL

git@git.e-strix.com:repositories/javafx-git-sample.git

W polu: Repository browser

gitlist

W polu: Repository browser -> URL

git.e-strix.com

W polu: Budowanie -> Invoke Gradle -> Version

Gradle_4_6

W polu: Budowanie -> Tasks

clean generateMyResources bootJar

Podnoszenie wersji

Kroki takie jak w przypadku „Budowa zdalna” z tą różnicą że w:

W polu: Budowanie -> Tasks

clean release --type minor

Gdzie wartość –type przyjmuje wartości:

  • major
  • minor
  • bugfix – domyślny

Publikacja na Landing Page

W polu: Budowanie -> Execute Shell -> Command

mkdir -p release_lib

rm -f ./release_lib/*

cp ${WORKSPACE}/../javafx-git-sample-release/build/libs/*.jar ./release_lib/

rm -f /home/appuser/public_html/download/*.jar

cp ./release_lib/*.jar /home/appuser/public_html/download/

Zakończenie

Jak widzisz storzenie projektu jest dość proste. Mimo że musiałem kilka godzin spędzić na odnalezieniu odpowiedniej dla mojego projektu ścieżki rozwoju. Przetestowałem kilka rozwiązań, pluginów i stwierdziłem że jednak najlepsze rozwiązanie to będzie ręczne napisanie skryptu (mimo że zapożyczyłem rozwiązanie od mądrych ludzi z internetu).