Setelah melewati proses development aplikasi, maka tahap berikutnya adalah melakukan deployment aplikasi ke server yang dituju. Sebelum melakukan deployment, maka aplikasi wajib dilakukan testing terlebih dahulu. Proses seperti testing, building dan deployment sebenarnya dapat dijalankan secara otomatis dengan menggunakan tool automated deployment misalnya seperti :

Untuk melakukan integrasi dari satu proses dengan proses lain misalnya seperti testing kemudian menjalankan building lalu mendeploy, dalam hal ini sering disebut dengan Continuous Integration. Di dalam proses Continuous Integration, terdapat 2 jenis yaitu :

  1. Continuous Deployment adalah proses deployment yang dijalankan secara otomatis mulai dari testing, building hingga deployment ke server production
  2. Continuous Delivery adalah proses deployment yang dijalankan secara otomatis mulai dari testing, building, akan tetapi untuk proses deployment akan dilakukan secara manual. Biasanya yang melakukan deployment ke server production adalah manager IT yang tertinggi untuk memastikan aplikasi berjalan lancar.

Pada artikel ini, penulis akan membahas bagaimana cara melakukan integrasi gitlab (git server) dengan jenkins. Source code yang telah di push ke gitlab nantinya akan diclone di jenkins server lalu dilakukan testing, jika sukses maka source code akan di deploy ke server production, dalam artikel ini penulis akan mencoba melakukan deployment otomatis ke heroku. Berikut adalah arsitektur yang akan penulis gunakan untuk membuat Continuous Deployment dengan menggunakan docker, gitlab dan jenkins.

Flow Gitlab Jenkins.svg

Setup Docker Compose

Bagi anda yang belum mengerti bagaimana cara menggunakan docker, silahkan baca di artikel Belajar Docker dan Belajar Load Balancing Dengan HAProxy, Docker Dan Spring Boot. Silahkan buat sebuah file docker-compose.yml lalu isikan source code seperti berikut.

version: '2'

services:
  gitlab:
    container_name: docker-gitlab
    image: gitlab/gitlab-ce
    ports:
      - 80:80
    networks:
      main:
        aliases:
          - gitlab

  jenkins:
    container_name: docker-jenkins
    image: jenkins/jenkins
    ports:
      - 8080:8080
    networks:
      main:
        aliases:
          - jenkins

networks:
  main:

Konfigurasi docker compose yang kita gunakan adalah versi 2. Disini penulis membuat 2 container yaitu docker-gitlab dengan base image gitlab/gitlab-ce dan docker-jenkins dengan base image jenkins/jenkins. Masing - masing container akan melakukan expose port sehingga kita dapat melakukan akses dari luar container. Pada konfigurasi diatas kita menggunakan fungsi networks, fungsi networks ini memungkinkan kita untuk mengakses 2 way dependency antar container, secara default sebenarnya kita dapat menggunakan fungsi links, akan tetapi jika menggunakan 2 way dependency link maka akan muncul error, untuk mengatasi hal diatas maka kita gunakan networks untuk menghubungkan 2 container dengan kebutuhan 2 way dependency. Dengan menggunakan network maka container jenkins dapat mengakses http://gitlab dan container gitlab dapat mengakses http://jenkins. Jika telah selesai, kita akan melakukan menjalankan 2 container diatas dengan perintah.

docker-compose up

Jika berhasil maka akan muncul output seperti berikut.

Screen Shot 2017-07-30 at 4.56.25 PM.png

Setup Jenkins

Ketika jenkins startup, jangan lupa untuk mencatat key security, biasanya terdapat pada baris berikut.

docker-jenkins | Jul 30, 2017 10:03:54 AM jenkins.install.SetupWizard init
docker-jenkins | INFO:
docker-jenkins |
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************
docker-jenkins |
docker-jenkins | Jenkins initial setup is required. An admin user has been created and a password generated.
docker-jenkins | Please use the following password to proceed to installation:
docker-jenkins |
docker-jenkins | a541f4e0f9f94dff807afb3273c260a1
docker-jenkins |
docker-jenkins | This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
docker-jenkins |
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************
docker-jenkins | *************************************************************

Dapat dilihat, bahwa key security yang akan kita gunakan nantinya adalah a541f4e0f9f94dff807afb3273c260a1. Jika anda melihat output seperti berikut.

docker-jenkins | --> setting agent port for jnlp
docker-jenkins | --> setting agent port for jnlp... done
docker-jenkins | Jul 30, 2017 10:04:02 AM hudson.model.UpdateSite updateData
docker-jenkins | INFO: Obtained the latest update center data file for UpdateSource default
docker-jenkins | Jul 30, 2017 10:04:04 AM hudson.model.DownloadService$Downloadable load
docker-jenkins | INFO: Obtained the updated data file for hudson.tasks.Maven.MavenInstaller
docker-jenkins | Jul 30, 2017 10:04:08 AM hudson.model.DownloadService$Downloadable load
docker-jenkins | INFO: Obtained the updated data file for hudson.tools.JDKInstaller
docker-jenkins | Jul 30, 2017 10:04:08 AM hudson.model.AsyncPeriodicWork$1 run
docker-jenkins | INFO: Finished Download metadata. 19,060 ms
docker-jenkins | Jul 30, 2017 10:04:11 AM hudson.model.UpdateSite updateData
docker-jenkins | INFO: Obtained the latest update center data file for UpdateSource default
docker-jenkins | Jul 30, 2017 10:04:11 AM hudson.WebAppMain$3 run
docker-jenkins | INFO: Jenkins is fully up and running

Ini menandakan bahwa jenkins adalah telah berjalan dan siap digunakan. Untuk gitlab, nantinya kita akan lakukan konfigurasi jika gitlab telah berjalan dengan sempurna, gitlab membutuhkan waktu yang lebih lama dikarenakan melakukan beberapa setup database dan lain sebagainya. Oke silahkan buka http://127.0.0.1:8080 di browser anda. Jika berhasil maka akan muncul output seperti berikut.

Screen Shot 2017-07-30 at 5.07.19 PM.png

Lalu silahkan isikan security key yang telah anda simpan. Jika berhasil maka akan muncul halaman Customize Jenkins untuk melakukan instalasi plugin, silahkan pilih install suggested plugins, nantinya anda akan dibawa ke halaman proses instalasi plugin seperti berikut.

Screen Shot 2017-07-30 at 5.12.20 PM.png

Jika instalasi plugin telah selesai, nantinya anda akan diarahkan ke halaman pengisian data administrator, silahkan isi sesuai dengan kebutuhan anda. Berikut adalah halaman awal ketika anda memasuki dashboard jenkins.

Screen Shot 2017-07-30 at 5.19.29 PM.png

Instalasi Plugin Gitlab

Langkah selanjutnya, karena kita menggunakan gitlab, maka kita harus melakukan instalasi plugin gitlab terlebih dahulu. Berikut adalah langkah - langkahnya.

  1. Silahkan pilih menu manage jenkins yang ada disebelah kanan anda.
  2. Lalu pilih menu manage plugins.
  3. Lalu pilih tab available
  4. Kemudian silahkan cari plugin GitLab Plugin, cek list lalu pilih install without restart
  5. Kemudian akan diarahkan ke halaman proses instalasi, silahkan cek list Restart Jenkins when installation is complete and no jobs are running agar jenkins melakukan restart setelah melakukan instalasi plugin tersebut.

Setup Gradle Dan JDK

Project yang akan penulis deploy adalah project berbasis gradle, maka kita perlu melakukan setup gradle dan juga jdk nya. Berikut adalah langkah - langkahnya.

  1. Silahkan pilih menu manage jenkins yang ada disebelah kanan anda.
  2. Lalu pilih menu Global Tool Configuration
  3. Pada menu JDK, silahkan pilih Add JDK
  4. Bagian name isikan dengan JDK 8, cek list pada agreement dan jangan lupa login dengan menggunakan oracle account.
  5. Pada menu gradle, silahkan pilih Add Gradle
  6. Bagian name isikan dengan Gradle 4.0.2.
  7. Jika telah selesai silahkan klik save.

Setup Gitlab

Langkah selanjutnya kita akan melakukan setup gitlab, silahkan akses http://127.0.0.1, secara default gitlab menggunakan port 80. Ketika anda mengakses pertama kali, anda akan diminta untuk mengisi password baru, silahkan isi dengan kebutuhan anda. Jika telah selesai, anda akan dipindahkan ke halaman login seperti berikut.

Screen Shot 2017-07-30 at 5.34.08 PM.png

Silahkan login dengan menggunakan user root dan password yang telah anda register kan pada halaman sebelumnya. Jika berhasil maka akan muncul halaman seperti berikut.

Screen Shot 2017-07-30 at 5.36.17 PM.png

Setup User Jenkins Pada Gitlab

Repository yang ada di dalam gitlab biasanya akan disetting menjadi private repository, sehingga hanya user tertentu yang dapat melakukan akses terhadap repository tersebut. Agar jenkins dapat melakukan akses repository tersebut maka kita harus melakukan register untuk user jenkins. Silahkan logout terlebih dahulu, lalu lakukan registrasi melalui halaman register gitlab. Setelah selesai, silahkan logout kembali lalu login kembali menggunakan user root. Silahkan buat sebuah group dengan nama jenkins-group lalu buat sebuah project di dalam jenkins-group dengan nama Belajar-Jenkins seperti gambar berikut.

Screen Shot 2017-07-30 at 5.47.02 PM.png

Setelah selesai, silahkan pilih menu admin area (gambar kunci) seperti berikut

Screen Shot 2017-07-30 at 5.48.40 PM

Maka akan muncul halaman baru, silahkan pilih group jenkins-group dibagian kanan bawah. Nantinya anda akan masuk ke halaman management user di dalam group tersebut, silahkan pilih user jenkins dan berikan hak akses sebagai owner seperti gambar berikut.

Screen Shot 2017-07-30 at 5.50.41 PM.png

Setup Credentials Pada Jenkins

Setelah membuat user pada gitlab, sekarang kita akan mencoba membuat credentials pada jenkins, sehingga nantinya jenkins dapat melakukan clone dan deployment otomatis ke heroku. Silahkan pilih menu credentials pada menu jenkins yang berada di bawah enu My views, maka akan muncul menu system yang telah di expand, silahkan pilih menu system tersebut. Lalu pilih domain Global credentials (unrestricted), dan kemudian pilih menu Add Credentials. Untuk user jenkins silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 6.18.11 PM.png

Untuk user heroku juga silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 6.20.17 PM.png

Yang terakhir, kita harus mendaftarkan api token gitlab pada jenkins, untuk membuat api token gitlab, silahkan login kembali ke gitlab dengan menggunakan user root, lalu pilih menu setting dan pilih tab access token. Lalu isikan seperti berikut.

Screen Shot 2017-07-30 at 6.22.56 PM.png

Jika sudah, nantinya akan muncul api token gitlab, kemudian silahkan isikan seperti berikut di menu jenkins.

Screen Shot 2017-07-30 at 6.24.02 PM.png

Berikut adalah list credentials yang didaftarkan.

Screen Shot 2017-07-30 at 6.25.56 PM.png

Setup Connection Jenkins Ke Gitlab

Agar jenkins dapat mengakses source code pada gitlab maka kita harus melakukan konfigurasi connection terlebih dahulu pada jenkins. Berikut adalah tahapan nya.

  1. Pilih menu manage jenkins.
  2. Lalu pilih configure system.
  3. Lalu isikan konfigurasi berikut pada menu gitlab

Screen Shot 2017-07-30 at 6.38.07 PM.png

Pada gitlab host URL, penulis menggunakan http://gitlab, ini disebabkan kita menggunakan network dari docker, sehingga untuk memanggil connection gitlab, kita dapat menggunakan url http://gitlab. Kemudian silahkan lakukan test connection, jika error silahkan periksa konfigurasinya kembali.

Setup Project Pada Heroku

Silahkan login pada dashboard heroku, lalu silahkan buat sebuah app, bebas dengan nama apa saja, misalnya disini saya membuat projectnya dengan nama belajar-jenkins. Maka nantinya url git yang digunakan akan menjadi git@heroku.com:belajar-jenkins.git

Membuat Project Pada Jenkins

Silahkan akses kembali dashboard jenkins, silahkan pilih menu create new jobs atau new item, lalu pilih menu Freestyle Project, nama project diisikan dengan Belajar-Jenkins lalu pilih oke. Untuk bagian general silahkan pilih gitlab connection seperti berikut.

Screen Shot 2017-07-30 at 6.41.02 PM.png

Pada source code management silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 9.19.29 PM.png

Screen Shot 2017-07-30 at 9.19.34 PM.png

Pada bagian rspec silahkan isikan sintak berikut untuk origin.

+refs/heads/*:refs/remotes/origin/* +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*

dan sintak berikut untuk heroku.

+refs/heads/*:refs/remotes/heroku/* +refs/merge-requests/*/head:refs/remotes/heroku/merge-requests/*

Pada bagian build triggers silahkan isikan seperti berikut.

Screen Shot 2017-07-30 at 6.45.18 PM.png

Pada bagian build environment silahkan pilih Delete workspace before build starts. Pada bagian build silahkan pilih add build step lalu pilih invoke gradle script. Pada bagian tasks silahkan isikan dengan perintah.

clean test

berikut adalah konfigurasi untuk invoke gradle

Screen Shot 2017-07-30 at 9.24.06 PM.png

Pada bagian Post-build Actions, silahkan pilih menu add post-build action, lalu pilih publish build status to gitlab commit, kemudian pilih menu git publisher, lalu silahkan ubah konfigurasinya menjadi seperti berikut.

Screen Shot 2017-07-30 at 6.51.31 PM.png

Screen Shot 2017-07-30 at 6.51.39 PM.png

Setup WebHook Pada Gitlab

Setiap 1 project yang ada di jenkins akan mewakili 1 project atau bahkan akan mewakili 1 branch yang ada di gitlab. Silahkan login kembali pada gitlab dengan user root, lalu pilih project yang akan didaftarkan webhook nya. Pilih menu setting pada projectnya, lalu pilih menu integrations kemudian isikan konfigurasinya seperti berikut.

Screen Shot 2017-07-30 at 7.07.08 PM.png

Kemudian lakukan test webhook nya, jika berhasil maka akan muncul output seperti berikut.

Hook execution failed. Ensure the project has commits.

Pesan diatas dikarenakan repository masih kosong dan belum ada source code yang dicommit.

Setup Project Yang Akan Di Deploy

Project yang akan kita deploy ke heroku adalah project spring boot dengan menggunakan kotlin, silahkan download terlebih dahulu projectnya di Belajar-Jenkins. Lalu silahkan extract project nya. Silahkan inisialisasi git pada project tersebut dengan perintah.

git init

Lalu inisialisasi remote git nya dengan perintah

git remote add origin http://127.0.0.1/jenkins-group/Belajar-Jenkins.git

lalu lakukan add semua project dengan perintah berikut.

git add .

lalu commit seperti berikut.

git commit -m "deploy jenkins"

Melakukan Deploy

Untuk melakukan deploy, silahkan lakukan push dengan perintah.

git push origin master

Ketika dijalankan teryata menyebabkan error, ini disebabkan karena ssh key yang ada di docker belum kita daftarkan pada heroku. Sebelumnya, kita akan melakukan instalasi heroku cli terlebih dahulu pada docker, untuk dapat mengakses ssh docker, kita membutuhkan id container yang sedang aktif. Silahkan jalan perintah berikut untuk mengetahui id nya.

docker ps

maka hasilnya akan seperti berikut.

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                 PORTS                                 NAMES
a794b66cca69        jenkins/jenkins     "/bin/tini -- /usr..."   3 hours ago         Up 3 hours             0.0.0.0:8080->8080/tcp, 50000/tcp     docker-jenkins
2cb159c58b5e        gitlab/gitlab-ce    "/assets/wrapper"        3 hours ago         Up 3 hours (healthy)   22/tcp, 443/tcp, 0.0.0.0:80->80/tcp   docker-gitlab

Untuk mengakses root container silahkan jalankan perintah berikut.

docker exec -u 0 -it a794b66cca69 bash

Kemudian silahkan jalankan perintah dibawah ini berdasarkan baris nya.

wget https://cli-assets.heroku.com/heroku-cli/channels/stable/heroku-cli-linux-x64.tar.gz -O heroku.tar.gz
$ tar -xvzf heroku.tar.gz
$ mkdir -p /usr/local/lib /usr/local/bin
$ mv heroku-cli-v6.x.x-darwin-64 /usr/local/lib/heroku
$ ln -s /usr/local/lib/heroku/bin/heroku /usr/local/bin/heroku

Setelah selesai, silahkan keluar dari ssh, kemudian login lagi ke ssh dengan perintah berikut.

docker exec -i -t a794b66cca69 /bin/bas

Kemudian lakukan login heroku dengan perintah.

heroku login

silahkan lakukan login dengan username dan password anda. Tahap selanjutnya, silahkan generate ssh anda dengan perintah.

ssh-keygen -t rsa -C "mufrizalrizki@gmail.com"

Lalu setting git nya dengan perintah

git config --global user.name "RizkiMufrizal"
git config --global user.email "mufrizalrizki@gmail.com"
git config --global color.ui true

Setelah selesai, silahkan jalankan perintah berikut untuk memunculkan public key.

cat ~/.ssh/id_rsa.pub

Kemudian hasilnya public key nya silahkan didaftarkan di heroku. Setelah selesai, coba lakukan clone repository dari heroku agar mendapatkan hak akses ssh nya dengan perintah.

git clone git@heroku.com:belajar-jenkins.git

Maka akan muncul info seperti berikut.

Cloning into 'belajar-jenkins'...
The authenticity of host 'heroku.com (50.19.85.132)' can't be established.
RSA key fingerprint is SHA256:8tF0wX2WquK45aGKs/Bh1dKmBXH08vxUe0VCJJWOA/o.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'heroku.com,50.19.85.132' (RSA) to the list of known hosts.

Silahkan ketik yes, maka project akan di clone dari heroku. Nah jika telah selesai, silahkan balik lagi ke dashboard project jenkins, silahkan pilih menu build now, sehingga jenkins akan menjalankan ulang proses test build dan deploy ke heroku.

Jika berhasil maka akan muncul output seperti berikut.

Screen Shot 2017-07-30 at 9.25.52 PM.png

Jika ingin melihat status pipeline yang ada di gitlab, silahkan login kembali dengan user root lalu akses project, pilih menu pipelines dan berikut adalah hasilnya.

Screen Shot 2017-07-30 at 9.29.58 PM.png

Untuk mengecek apakah sudah berhasil di deploy atau belum, silahkan cek di https://{nama-aplikasi-heroku}.herokuapp.com/api/barangs, karena saya menggunakan belajar-jenkins, maka saya mengakses nya di https://belajar-jenkins.herokuapp.com/api/barangs dan berikut adalah hasilnya.

Screen Shot 2017-07-30 at 9.28.27 PM.png

Jika sewaktu - waktu terjadi error pada saat testing, maka jenkins akan mengeluarkan pesan error dan deployment ke production tidak akan dilakukan, berikut output jika testing error.

Screen Shot 2017-07-30 at 9.42.22 PM.png

Dan berikut jika output yang akan ditampilkan pada gitlab.

Screen Shot 2017-07-30 at 9.42.25 PM.png

Sekian artikel mengenai Belajar Melakukan Integrasi Jenkins Dan Gitlab Pada Docker, jika ada pertanyaan atau saran silahkan isi di kolom komentar dan Terima kasih :).

Pada artikel sebelumnya telah membahas mengenai angular js. Yups angular js adalah salah satu framework yang dikembangkan oleh google. Akan tetapi sejak angular versi 2, google hanya memberikan nama dengan angular, sedangkan untuk versi 1 mereka menamakan nya dengan angular js. Jika Anda menggunakan angular js maka kita menggunakan bahasa pemrograman javascript, sedangkan jika kita menggunakan angular 2 atau 4 maka nantinya kita akan menggunakan typescript.

Apa Itu TypeScrypt ?

TypeScrypt adalah bahasa pemrograman yang dikembangkan oleh microsoft, dimana TypeScrypt memiliki fitur strong-typing sehingga membuat developer lebih rapi dalam melakukan development sebuah aplikasi.

Jika Anda adalah seorang developer java, maka tidak perlu memiliki waktu lama untuk menguasai TypeScrypt. Sintak yang digunakan juga tidak jauh berbeda dengan javascript. Salah satu yang penulis sukai adalah terdapat autocomplete yang bisa kita gunakan jika kita menggunakan editor visual studio code untuk melakukan development dengan TypeScrypt.

Setup Project Angular 4

Pada artikel ini, penulis akan membuatkan sebuah artikel mengenai bagaimana setup project angular 4. Bagi Anda yang belum melakukan instalasi node js, silahkan lihat artikel nya di Instalasi Perlengkapan Coding Node JS. Untuk membuat project angular 4, kita dapat menggunakan bantuan angular cli. Untuk melakukan instalasi angular 4, silahkan jalankan perintah berikut.

npm install -g @angular/cli

Jika telah selesai, tahap selanjutnya kita akan membuat sebuah project angular 4 dengan perintah berikut.

ng new Belajar-Angular4

Jika berhasil maka project nya akan memiliki struktur folder seperti berikut.

Screen Shot 2017-07-08 at 10.59.12 PM.png

Untuk menjalankan projectnya, silahkan jalankan perintah berikut.

ng serve

Nantinya akan dilakukan compile dan dilakukan transpiler dari TypeScrypt ke javascript versi ES5. Jika telah selesai, silahkan akses url http://localhost:4200 di browser Anda.

Membuat Hello Word Dengan Angular 4

Silahkan buka folder app yang terdapat di dalam folder src. Silahkan buka file app.component.html lalu ubah menjadi seperti berikut.

<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
  <h1>
    Welcome to {{title}}!!
  </h1>
  <img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo=">
</div>

<input [(ngModel)]="nama" />

<h1>Hello {{nama}}</h1>

dari codingan diatas, dapat dilihat bahwa kita menggunakan directive ngModel dimana nantinya isi dari property nama akan dibinding ke <h1>Hello {{nama}}</h1> .

Jika langsung dijalankan maka akan muncul error, error disini disebabkan kita belum melakukan import untuk module FormsModule, untuk melakukan module tersebut, silahkan buka file app.module.ts lalu ubah codingan nya menjadi seperti berikut.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Setelah selesai, silahkan akses kembali http://localhost:4200 di browser anda, disana terdapat 1 inputan, silahkan isikan nama anda, jika berhasil maka akan muncul output seperti berikut.

Screen Shot 2017-07-08 at 11.25.44 PM.png

Sekian artikel mengenai Setup Project Angular 4 dan Terima kasih :)

Apa Itu Secret Storage ?

Secret Storage adalah suatu storage yang berfungsi untuk menyimpan data - data secret / rahasia misalnya seperti password, API Key, client id, client secret dan lain - lain.

Sebagai seorang developer, terutama backend developer, mereka biasanya akan membuat sebuah environment. Environment ini biasanya digunakan untuk menyimpan data - data penting misalnya seperti IP database, nama database, username dan juga password dari database. Secara tidak langsung, membuat environment seperti hal diatas sebenarnya merupakan hal yang mengerikan jika suatu waktu server yang kita gunakan dapat dibobol oleh pihak yang tidak berkepentingan sehingga file environment tersebut dapat dibaca. Bahaya lagi jika pihak tersebut dapat mengakses database dan mengunci data - data nya sehingga kita diharuskan membayar kepada mereka agar datanya dapat dikembalikan.

Untuk mengatasi hal diatas, kita harus menggunakan suatu database, dimana pada database tersebut kita dapat menyimpan nilai - nilai secret tersebut secara aman. Pada artikel ini, penulis akan membahas salah satu secret storage yang banyak digunakan dikalangan developer yaitu Vault.

Apa Itu Vault ?

Vault adalah tool untuk management secret suatu nilai yang dikembangkan oleh HashiCorp.

Biasanya vault akan digunakan untuk menyimpan data - data yang bersifat secret / rahasia misalnya seperti username, password, nama database dan IP dari suatu database. Vault memiliki banyak kelebihan diantaranya adalah Semua data yang disimpan ke dalam vault bersifat encrypted sehingga tidak dapat dibaca dan untuk dapat mengakses suatu data dari vault wajib menggunakan token.

Instalasi Vault

Untuk melakukan instalasi vault, silahkan download vault disini. Setelah download maka anda akan mendapatkan sebuah file, karena penulis menggunakan OSX maka nama file nya adalah vault_0.7.3_darwin_amd64.zip. Silahkan extract disuatu folder, lalu agar vault terbaca di terminal maka kita harus melakukan export path pada bash atau zsh. Silahkan jalankan perintah berikut untuk membuka file .zshrc.

vim ~/.zshrc

Jika menggunakan bash maka anda dapat menggunakan perintah.

vim ~/.bash_profile

Kemudian masukkan codingan berikut pada baris yang paling atas.

export PATH=$PATH:/Users/rizkimufrizal/vault/
export VAULT_ADDR='http://127.0.0.1:8200'

Pada codingan diatas, kita melakukan export path untuk vault, silahkan sesuaikan path vault anda. Pada baris kedua, penulis mendeklarasikan VAULT_ADDR, biasanya konfigurasi ini digunakan untuk vault client yang akan berkomunikasi dengan vault server. Langkah selanjutnya, silahkan update .zshrc dengan perintah.

source .zshrc

atau jika anda menggunakan bash :

source .bash_profile

Lalu selanjutnya jalankan server vault, karena sekarang masih tahap development, maka cara menjalankan seperti berikut.

vault server -dev

Lalu untuk mengecek apakah server vault telah jalan atau tidak, silahkan jalankan perintah berikut.

vault status

Jika berhasil maka akan muncul output seperti berikut.

Sealed: false
Key Shares: 1
Key Threshold: 1
Unseal Progress: 0
Unseal Nonce:
Version: 0.7.3
Cluster Name: vault-cluster-dea4df0a
Cluster ID: 4a9ba1e3-2638-e2a0-3f03-c3afc6e3c93e

High-Availability Enabled: false

Silahkan buka terminal anda, lalu jalankan perintah berikut.

vault write secret/belajar value=rizkimufrizal

Pada contoh diatas, kita menulis sebuah nilai yaitu rizkimufrizal, dimana nilai tersebut ditulis pada path/key secret/belajar. Jika anda memiliki banyak nilai, lebih baik anda menggunakan file json yang dapat diimport ke vault, silahkan buat file json dengan nama file vault.json, lalu masukkan codingan seperti berikut.

{
    "spring": {
        "datasource": {
            "url": "jdbc:mariadb://127.0.0.1:3306/microservice_book?autoReconnect=true",
            "username": "root",
            "password": "admin"
        }
    }
}

Pada codingan json diatas, dapat kita lihat bahwa kita membuat banyak object, diantaranya ada object spring, datasource dan lain - lain, dimana pada codingan diatas kita menyimpan data - data url, username dan password. Untuk melakukan import ke vault, silahkan jalankan perintah berikut.

vault write secret/belajar @vault.json

Untuk membaca nilai dari diatas, silahkan jalankan perintah berikut.

vault read secret/belajar

Maka hasilnya akan seperti berikut.

Key             	Value
---             	-----
refresh_interval	768h0m0s
spring          	map[datasource:map[password:admin url:jdbc:mariadb://127.0.0.1:3306/microservice_book?autoReconnect=true username:root]]

Agar mempermudah membaca value nya, silahkan jalankan perintah berikut untuk menghasilkan output json.

vault read -format=json secret/belajar

dan hasilnya akan seperti berikut.

{
    "request_id": "5f185fff-0ec5-3974-f7a8-568c4457bc1b",
    "lease_id": "",
    "lease_duration": 2764800,
    "renewable": false,
    "data": {
        "spring": {
            "datasource": {
                "password": "admin",
                "url": "jdbc:mariadb://127.0.0.1:3306/microservice_book?autoReconnect=true",
                "username": "root"
            }
        }
    },
    "warnings": null
}

Bagaimana Cara Akses Melalui Aplikasi ?

Untuk mengakses value tersebut, kita bisa menggunakan fungsi token yang disediakan oleh vault, silahkan jalankan perintah berikut untuk membuat sebuah token.

vault token-create

Jika berhasil maka akan muncul output seperti berikut.

Key            	Value
---            	-----
token          	09cb9604-f9df-c3bc-6e0c-dc1d3bd3a1fc
token_accessor 	8a95c580-3fb0-6551-f0ba-e77516fdd906
token_duration 	0s
token_renewable	false
token_policies 	[root]

Biasanya token yang digunakan adalah 09cb9604-f9df-c3bc-6e0c-dc1d3bd3a1fc. Setiap bahasa pemrograman memiliki library tersendiri untuk dapat mengakses vault, silahkan lihat list library tersebut disini.

Implementasi Akses Vault Dengan Spring Framework

Pada artikel ini, penulis akan melakukan implementasi dengan menggunakan Spring Vault. Silahkan buat sebuah project spring boot melalui Spring Initializr, Silahkan isikan property menjadi seperti berikut.

Screen Shot 2017-06-19 at 11.23.06 AM.png

Silahkan download dan import ke IDE anda. Lalu ubah codingan pada file build.gradle menjadi seperti berikut.

buildscript {
    ext {
        kotlinVersion = "1.1.2-5"
        springBootVersion = "1.5.4.RELEASE"
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
    }
}

apply plugin: "kotlin"
apply plugin: "kotlin-spring"
apply plugin: "eclipse"
apply plugin: "org.springframework.boot"

version = "0.0.1-SNAPSHOT"
sourceCompatibility = 1.8
compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

repositories {
    mavenCentral()
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter")
    compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}")
    compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    compile("org.springframework.vault:spring-vault-core:1.0.2.RELEASE")
    testCompile("com.winterbe:expekt:0.5.0")
    testCompile("org.springframework.boot:spring-boot-starter-test")
}

Setelah selesai, silahkan buka file application.properties yang ada di dalam folder resources, lalu masukkan konfigurasi vault seperti berikut.

vault.token = 09cb9604-f9df-c3bc-6e0c-dc1d3bd3a1fc
vault.url = http://127.0.0.1:8200

Selanjutnya silahkan buat sebuah package configuration lalu buat sebuah class kotlin didalam nya dengan nama VaultConfiguration lalu masukkan codingan seperti berikut.

package org.rizki.mufrizal.belajar.spring.vault.configuration

import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.PropertySource
import org.springframework.vault.authentication.ClientAuthentication
import org.springframework.vault.authentication.TokenAuthentication
import org.springframework.vault.client.VaultEndpoint
import org.springframework.vault.config.AbstractVaultConfiguration
import java.net.URI

/**
 * Created by rizkimufrizal on 6/19/17.
 */
@Configuration
@PropertySource("classpath:application.properties")
class VaultConfiguration : AbstractVaultConfiguration() {
    override fun clientAuthentication(): ClientAuthentication = TokenAuthentication(environment.getRequiredProperty("vault.token"))

    override fun vaultEndpoint(): VaultEndpoint = VaultEndpoint.from(URI(environment.getRequiredProperty("vault.url")))
}

Codingan diatas berfungsi sebagai konfigurasi dari vault, dimana kita melakukan set token terlebih dahulu agar dapat nilai secret nya dapat diakses. Selanjutnya silahkan buka main class lalu masukkan codingan seperti berikut.

package org.rizki.mufrizal.belajar.spring.vault

import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.core.env.Environment
import org.springframework.vault.annotation.VaultPropertySource

@SpringBootApplication
@VaultPropertySource(value = "secret/belajar")
class BelajarSpringVaultApplication @Autowired constructor(val environment: Environment) : CommandLineRunner {
    private val logger = LoggerFactory.getLogger(BelajarSpringVaultApplication::class.java)

    override fun run(vararg args: String?) {
        logger.info("hasil secret dari url : ${environment.getRequiredProperty("spring.datasource.url")}")
        logger.info("hasil secret dari username : ${environment.getRequiredProperty("spring.datasource.username")}")
        logger.info("hasil secret dari password : ${environment.getRequiredProperty("spring.datasource.password")}")
    }
}

fun main(args: Array<String>) {
    SpringApplication.run(BelajarSpringVaultApplication::class.java, *args)
}

Berikut adalah penjelasan mengenai codingan diatas :

  • @VaultPropertySource berfungsi untuk mengambil secret berdasarkan path / key, tadi kita telah menyimpan sebuah nilai secret pada secret/belajar.
  • environment.getRequiredProperty("spring.datasource.url") berfungsi untuk mengambil nilai yang berasal dari key spring.datasource.url, jadi key yang diambil harus sesuai dengan key yang dibuat.

Oke, selanjutnya kita akan membuat sebuah test untuk memastikan bahwa environment yang dibaca adalah benar, silahkan buka file BelajarSpringVaultApplicationTests yang ada didalam package test, lalu ubah menjadi seperti berikut.

package org.rizki.mufrizal.belajar.spring.vault

import com.winterbe.expekt.should
import org.junit.Test
import org.junit.runner.RunWith
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.core.env.Environment
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.vault.annotation.VaultPropertySource

@RunWith(SpringRunner::class)
@SpringBootTest
@VaultPropertySource(value = "secret/belajar")
class BelajarSpringVaultApplicationTests {

    @Autowired
    lateinit var environment: Environment

    private val logger = LoggerFactory.getLogger(BelajarSpringVaultApplicationTests::class.java)

    @Test
    fun testUrl() {
        logger.info("begin test url")
        environment.getRequiredProperty("spring.datasource.url").should.equal("jdbc:mariadb://127.0.0.1:3306/microservice_book?autoReconnect=true")
        environment.getRequiredProperty("spring.datasource.url").should.not.`null`
        environment.getRequiredProperty("spring.datasource.url").should.not.`empty`
        logger.info("end test url")
    }

    @Test
    fun testUsername() {
        logger.info("begin test username")
        environment.getRequiredProperty("spring.datasource.username").should.equal("root")
        environment.getRequiredProperty("spring.datasource.username").should.not.`null`
        environment.getRequiredProperty("spring.datasource.username").should.not.`empty`
        logger.info("end test username")
    }

    @Test
    fun testPassword() {
        logger.info("begin test password")
        environment.getRequiredProperty("spring.datasource.password").should.equal("admin")
        environment.getRequiredProperty("spring.datasource.password").should.not.`null`
        environment.getRequiredProperty("spring.datasource.password").should.not.`empty`
        logger.info("end test password")
    }
}

Jika menggunakan terminal, silahkan jalankan dengan perintah berikut.

gradle test

Jika menggunakan Intellij IDEA, klik kanan pada class test, lalu pilih run seperti berikut.

Screen Shot 2017-06-19 at 1.15.09 PM.png

Dan berikut adalah hasil test nya.

Screen Shot 2017-06-19 at 1.15.47 PM.png

Sekian artikel mengenai Belajar Secret Storage Dengan Vault dan Terima kasih :). Untuk source code lengkap, penulis publish di Belajar Secret Storage Dengan Vault.

Pada artikel sebelumnya, penulis telah membahas mengenai setup project kotlin dengan menggunakan gradle. Nah pada artikel ini, penulis akan membahas sedikit mengenai null safety pada kotlin.

Apa Itu Null Safety

Sebagai developer java, anda pasti sering menemui yang namanya NullPointerException atau disingkat dengan NPE. Terkadang kita akan mengecek seluruh object apakah terdapat potensi NPE atau tidak dan NPE ini sangat sering terjadi terutama jika anda adalah android developer. Pada kotlin, anda dapat membedakan antara variabel yang boleh null dan yang tidak boleh null. Supaya lebih memahami, silahkan buka project yang dulu pernah anda buat, lalu buatlah sebuah file kotlin di dalam package org.rizki.mufrizal.belajarKotlin dengan nama NullSafety. Kemudian isikan codingan seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            var nama = "rizki"
            nama = null //error
            print("hello $nama")
        }
    }
}

Dari codingan diatas, maka secara otomatis codingan anda akan error seperti berikut.

Screen Shot 2017-06-12 at 9.57.17 AM.png

Error ini disebabkan karena secara default variabel pada kotlin tidak boleh diisi dengan null, sehingga dengan error ini developer lebih dapat mengatasi NPE. Agar variabel diatas dapat diisi dengan null maka silahkan ubah codingan nya menjadi seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            var nama: String? = "rizki"
            nama = null
            print("hello $nama")
        }
    }
}

Tanda dari ? berfungsi agar variabel tersebut dapat diisi dengan null. Oke langkah selanjutnya adalah ketika anda ingin mengetahui panjang dari suatu string, biasanya kita akan menggunakan function dari length, Jika anda menggunakan tanda ? maka setiap mengakses function length maka anda wajib juga menyertakan tanda ?, di IntelliJ IDEA, ketika anda mencoba mengakses function length tanpa tanda ? maka warna nya akan gelap pertanda bahwa anda diwajibkan menggunakan tanda ? seperti berikut.

Screen Shot 2017-06-12 at 10.08.52 AM.png

Jika anda tidak menggunakan tanda ? maka akan compiler akan memberitahukan error karena variabel memiliki nilai null. Untuk mengatasi hal demikian, silahkan ubah codingan menjadi seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            var nama: String? = "rizki"
            nama = null
            print("hello $nama dengan panjang nama : ${nama?.length}")
        }
    }
}

Untuk mempermudah melakukan test, silahkan ubah codingan diatas menjadi seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {

    fun nullOrNot(text: String?) = "hello $text dengan panjang text : ${text?.length}"

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println(NullSafety().nullOrNot(text = "rizki"))
            println(NullSafety().nullOrNot(text = null))
        }
    }
}

Jika pada codingan sebelumnya kita langsung melakukan print, maka pada codingan ini kita mendeklarasikan sebuah function dengan mengembalikan type data string. Pada function nullOrNot terdapat 1 parameter yaitu text dimana parameter ini dapat diisi dengan null dikarenakan menggunakan tanda ?. Untuk mengembalikan data dalam bentuk string, kita dapat langsung melakukan return jika codingan hanya sebaris seperti codingan diatas dan tanpa perlu menggunakan keyword return.

Langkah selanjutnya, kita akan membuat test nya, silahkan buat sebuah kotlin file dengan nama NullSafetyTest di dalam package test, kemudian isikan codingan seperti berikut.

package org.rizki.mufrizal.belajarKotlin

import com.winterbe.expekt.should
import org.jetbrains.spek.api.Spek
import org.jetbrains.spek.api.dsl.given
import org.jetbrains.spek.api.dsl.it
import org.jetbrains.spek.api.dsl.on

/**
 * Created by rizkimufrizal on 6/12/17.
 */
class NullSafetyTest : Spek({
    given("a class NullSafety") {
        val nullSafety = NullSafety()
        on("set text to not null") {
            val textNotNull = nullSafety.nullOrNot(text = "rizki")
            it("should return not null") {
                textNotNull.should.equal("hello rizki dengan panjang text : 5")
            }
        }
        on("set text to null") {
            val textNull = nullSafety.nullOrNot(text = null)
            it("should return null") {
                textNull.should.equal("hello null dengan panjang text : null")
            }
        }
    }
})

Memeriksa Null

Jika kita menggunakan tanda ? maka jika anda mengakses suatu function contohnya length maka kita akan mendapatkan output null, terkadang kita ingin mengambalikan value yang lain. Alaternatif lain adalah dengan menggunakan fungsi if. Silahkan edit source code yang ada pada class NullSafety seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {

    fun nullOrNot(text: String?) = "hello $text dengan panjang text : ${text?.length}"

    fun nullOrNotIf(text: String?) = if (text != null) "hello $text dengan panjang text : ${text.length}" else "Kosong / Isinya null"

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println(NullSafety().nullOrNot(text = "rizki"))
            println(NullSafety().nullOrNot(text = null))
            println(NullSafety().nullOrNotIf(text = "mufrizal"))
            println(NullSafety().nullOrNotIf(text = null))
        }
    }
}

Pada kodingan diatas kita ada penambahan 1 function yaitu nullOrNotIf dimana sebenarnya function ini juga sama dengan function nullOrNot, bedanya yaitu pada function ini kita melakukan pengecekan null terhadap variabel text sehingga pada saat kita mengakses function length dari variabel text, kita tidak perlu lagi menggunakan tanda ?. Jika kita memasukkan null, maka nantinya akan dicetak Kosong / Isinya null sedangkan jika tidak null maka akan dicetak kalimat hello mufrizal dengan panjang text : 8.

Selain menggunakan if else, untuk mengecek null, kita juga dapat menggunakan elvis, silahkan ubah codingan seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {

    fun nullOrNot(text: String?) = "hello $text dengan panjang text : ${text?.length}"

    fun nullOrNotIf(text: String?) = if (text != null) "hello $text dengan panjang text : ${text.length}" else "Kosong / Isinya null"

    fun nullOrNotElvis(text: String?): String {
        val length = text?.length ?: 0
        return if (length != 0) "hello $text dengan panjang text : $length" else "Kosong / Isinya null"
    }

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println(NullSafety().nullOrNot(text = "rizki"))
            println(NullSafety().nullOrNot(text = null))
            println(NullSafety().nullOrNotIf(text = "mufrizal"))
            println(NullSafety().nullOrNotIf(text = null))
            println(NullSafety().nullOrNotElvis(text = "rizki mufrizal"))
            println(NullSafety().nullOrNotElvis(text = null))
        }
    }
}

Dengan menggunakan elvis, kita hanya perlu menggunakan operator ?:, sintak ini mirip dengan ternary operator. Jika text?.length tidak null maka akan dikembalikan nilai text?.length, sedangkan jika null maka akan dikembalikan nilai 0.

Dan yang terakhir adalah adanya operator !!, biasanya operator ini berfungsi untuk mengembalikan data yang benar - benar tidak null, jika null maka akan menghasilkan error, berikut adalah contoh penggunaan !!, silahkan ubah source code seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {

    fun nullOrNot(text: String?) = "hello $text dengan panjang text : ${text?.length}"

    fun nullOrNotIf(text: String?) = if (text != null) "hello $text dengan panjang text : ${text.length}" else "Kosong / Isinya null"

    fun nullOrNotElvis(text: String?): String {
        val length = text?.length ?: 0
        return if (length != 0) "hello $text dengan panjang text : $length" else "Kosong / Isinya null"
    }

    fun nullOrNotNew(text: String?) = "hello $text dengan panjang text : ${text!!.length}"

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println(NullSafety().nullOrNot(text = "rizki"))
            println(NullSafety().nullOrNot(text = null))
            println(NullSafety().nullOrNotIf(text = "mufrizal"))
            println(NullSafety().nullOrNotIf(text = null))
            println(NullSafety().nullOrNotElvis(text = "rizki mufrizal"))
            println(NullSafety().nullOrNotElvis(text = null))
            println(NullSafety().nullOrNotNew(text = "mufrizal rizki"))
        }
    }
}

oke langkah selanjutnya kita akan membuat test nya, silahkan ubah source code yang ada di dalam file NullSafetyTest seperti berikut.

package org.rizki.mufrizal.belajarKotlin

import com.winterbe.expekt.should
import org.jetbrains.spek.api.Spek
import org.jetbrains.spek.api.dsl.given
import org.jetbrains.spek.api.dsl.it
import org.jetbrains.spek.api.dsl.on

/**
 * Created by rizkimufrizal on 6/12/17.
 */
class NullSafetyTest : Spek({
    given("a class NullSafety") {
        val nullSafety = NullSafety()
        on("set text to not null") {
            val textNotNull = nullSafety.nullOrNot(text = "rizki")
            it("should return not null") {
                textNotNull.should.equal("hello rizki dengan panjang text : 5")
            }
        }
        on("set text to null") {
            val textNull = nullSafety.nullOrNot(text = null)
            it("should return null") {
                textNull.should.equal("hello null dengan panjang text : null")
            }
        }
        on("set text to not null if") {
            val textNull = nullSafety.nullOrNotIf(text = "mufrizal")
            it("should return null") {
                textNull.should.equal("hello mufrizal dengan panjang text : 8")
            }
        }
        on("set text to null if") {
            val textNull = nullSafety.nullOrNotIf(text = null)
            it("should return null") {
                textNull.should.equal("Kosong / Isinya null")
            }
        }
        on("set text to not null elvis") {
            val textNull = nullSafety.nullOrNotElvis(text = "rizki mufrizal")
            it("should return null") {
                textNull.should.equal("hello rizki mufrizal dengan panjang text : 14")
            }
        }
        on("set text to null elvis") {
            val textNull = nullSafety.nullOrNotElvis(text = null)
            it("should return null") {
                textNull.should.equal("Kosong / Isinya null")
            }
        }
        on("set text to not null !!") {
            val textNull = nullSafety.nullOrNotNew(text = "mufrizal rizki")
            it("should return null") {
                textNull.should.equal("hello mufrizal rizki dengan panjang text : 14")
            }
        }
    }
})

Memeriksa Null Pada Collections

Terkadang ketika memasukkan suatu nilai ke sebuah collection, nilai tersebut dapat berupa null. Jika menggunakan kotlin, terdapat function filterNotNull yang berfungsi untuk menghilangkan value null yang terdapat di dalam collection. Silahkan ubah codingan nya menjadi seperti berikut.

package org.rizki.mufrizal.belajarKotlin

/**
 * Created by rizkimufrizal on 6/12/17.
 */

class NullSafety {

    fun nullOrNot(text: String?) = "hello $text dengan panjang text : ${text?.length}"

    fun nullOrNotIf(text: String?) = if (text != null) "hello $text dengan panjang text : ${text.length}" else "Kosong / Isinya null"

    fun nullOrNotElvis(text: String?): String {
        val length = text?.length ?: 0
        return if (length != 0) "hello $text dengan panjang text : $length" else "Kosong / Isinya null"
    }

    fun nullOrNotNew(text: String?) = "hello $text dengan panjang text : ${text!!.length}"

    fun filterCollection(list: List<*>) = list.filterNotNull()

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println(NullSafety().nullOrNot(text = "rizki"))
            println(NullSafety().nullOrNot(text = null))
            println(NullSafety().nullOrNotIf(text = "mufrizal"))
            println(NullSafety().nullOrNotIf(text = null))
            println(NullSafety().nullOrNotElvis(text = "rizki mufrizal"))
            println(NullSafety().nullOrNotElvis(text = null))
            println(NullSafety().nullOrNotNew(text = "mufrizal rizki"))

            val list = mutableListOf<String?>()
            list.add("rizki")
            list.add("mufrizal")
            list.add(null)

            val listNotNull = NullSafety().filterCollection(list)
            listNotNull.forEach { println("Nama Saya $it") }
        }
    }
}

Pada codingan diatas terdapat tambahan yaitu tambahan function filterCollection, dimana didalam function tersebut dilakukan filter terhadap list dengan type data bebas, mengapa bebas ? ini dikarenakan kita menggunakan tanda * atau sama juga dengan generic. Untuk melakukan perulangan terhadap variabel listNotNull maka dapat menggunakan function forEach. Disini saya menggunakan variabel it, variabel it sebenarnya variabel yang mengembalikan nilai dari perulangan variabel listNotNull. Jadi variabel it tergantung dari type data yang ada di dalam list tersebut.

Tahap selanjutnya kita membuat test nya, silahkan ubah codingan NullSafetyTest seperti berikut.

package org.rizki.mufrizal.belajarKotlin

import com.winterbe.expekt.should
import org.jetbrains.spek.api.Spek
import org.jetbrains.spek.api.dsl.given
import org.jetbrains.spek.api.dsl.it
import org.jetbrains.spek.api.dsl.on

/**
 * Created by rizkimufrizal on 6/12/17.
 */
class NullSafetyTest : Spek({
    given("a class NullSafety") {
        val nullSafety = NullSafety()
        on("set text to not null") {
            val textNotNull = nullSafety.nullOrNot(text = "rizki")
            it("should return not null") {
                textNotNull.should.equal("hello rizki dengan panjang text : 5")
            }
        }
        on("set text to null") {
            val textNull = nullSafety.nullOrNot(text = null)
            it("should return null") {
                textNull.should.equal("hello null dengan panjang text : null")
            }
        }
        on("set text to not null if") {
            val textNull = nullSafety.nullOrNotIf(text = "mufrizal")
            it("should return null") {
                textNull.should.equal("hello mufrizal dengan panjang text : 8")
            }
        }
        on("set text to null if") {
            val textNull = nullSafety.nullOrNotIf(text = null)
            it("should return null") {
                textNull.should.equal("Kosong / Isinya null")
            }
        }
        on("set text to not null elvis") {
            val textNull = nullSafety.nullOrNotElvis(text = "rizki mufrizal")
            it("should return null") {
                textNull.should.equal("hello rizki mufrizal dengan panjang text : 14")
            }
        }
        on("set text to null elvis") {
            val textNull = nullSafety.nullOrNotElvis(text = null)
            it("should return null") {
                textNull.should.equal("Kosong / Isinya null")
            }
        }
        on("set text to not null !!") {
            val textNull = nullSafety.nullOrNotNew(text = "mufrizal rizki")
            it("should return null") {
                textNull.should.equal("hello mufrizal rizki dengan panjang text : 14")
            }
        }
        on("set collection filter") {
            val list = mutableListOf<String?>()
            list.add("rizki")
            list.add("mufrizal")
            list.add(null)
            val collectionNotNull = nullSafety.filterCollection(list)
            it("should return collection not null") {
                collectionNotNull.should.not.`null`
                collectionNotNull.should.any.elements("rizki", "mufrizal")
                collectionNotNull.should.have.all.elements("rizki", "mufrizal")
                collectionNotNull.should.have.size.equal(2)
                collectionNotNull.should.have.size.above(1)
            }
        }
    }
})

Untuk melakukan test diatas, silahkan jalankan perintah berikut.

gradle test

dan berikut hasilnya.

:compileKotlin
Using kotlin incremental compilation
:compileJava NO-SOURCE
:copyMainKotlinClasses
:processResources NO-SOURCE
:classes UP-TO-DATE
:compileTestKotlin
Using kotlin incremental compilation
:compileTestJava NO-SOURCE
:copyTestKotlinClasses
:processTestResources NO-SOURCE
:testClasses UP-TO-DATE
:junitPlatformTest

Test run finished after 5131 ms
[        14 containers found      ]
[         0 containers skipped    ]
[        14 containers started    ]
[         0 containers aborted    ]
[        14 containers successful ]
[         0 containers failed     ]
[         9 tests found           ]
[         0 tests skipped         ]
[         9 tests started         ]
[         0 tests aborted         ]
[         9 tests successful      ]
[         0 tests failed          ]

:test SKIPPED

BUILD SUCCESSFUL

Total time: 13.815 secs

Sekian artikel mengenai mengenal null safety pada kotlin, jika ada saran dan komentar silahkan isi dibawah dan terima kasih :)

Pada artikel instalasi perlengkapan coding kotlin, penulis telah membahas sedikit mengenai bagaimana cara instalasi kotlin dengan sdkman. Oke, pada artikel ini, penulis akan membahas mengenai dasar - dasar dari bahasa pemrograman kotlin. Project yang akan kita buat adalah berbasis gradle, jika anda pengguna linux dan windows silahkan ikutin tutorial langsung dari websitenya disini. Untuk penggunakan OSX, anda dapat melakukan instalasi dengan bantuan Homebrew seperti berikut.

brew install gradle

Seperti biasa, penulis menggunakan IDE IntelliJ IDEA, anda dapat menggunakan versi community maupun versi ultimate karena dua - dua nya telah mendukung bahasa pemrograman kotlin.

Silahkan buka IDE anda, lalu untuk membuat sebuah project silahkan pilih menu create new project, lalu pilih gradle dan cek list di bagian kotlin seperti gambar berikut.

Screen Shot 2017-06-03 at 9.51.09 PM.png

Lalu pilih next, di bagian groupid silahkan isikan org.rizki.mufrizal.belajar.kotlin dan pada bagian artifact nya isikan dengan Belajar-Kotlin, lalu klik next hingga akan muncul project location, silahkan sesuaikan dengan folder project anda dan klik finish. Berikut adalah project yang berhasil digenerate oleh IntelliJ IDEA.

Screen Shot 2017-06-03 at 9.58.37 PM.png

Secara default, project belum memiliki package untuk class - class kotlin, silahkan akses project anda dengan menggunakan terminal, lalu jalankan perintah berikut.

mkdir -p src/main/kotlin/org/rizki/mufrizal/belajarKotlin
mkdir -p src/test/kotlin/org/rizki/mufrizal/belajarKotlin

Silahkan lihat kembali project anda yang ada di IntelliJ IDEA, maka akan terbentuk 2 sub directory dari src yaitu main untuk source code nya, sedangkan test untuk keperluan testing. Langkah selanjutnya silahkan buka file build.gradle lalu ubah menjadi seperti berikut.

group "org.rizki.mufrizal.belajar.kotlin"
version "1.0-SNAPSHOT"

buildscript {
    ext.kotlin_version = "1.1.2-4"

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.junit.platform:junit-platform-gradle-plugin:1.0.0-M4"
    }
}

apply plugin: "kotlin"
apply plugin: "org.junit.platform.gradle.plugin"

junitPlatform {
    filters {
        engines {
            include "spek"
        }
    }
}

repositories {
    mavenCentral()
    maven { url "http://dl.bintray.com/jetbrains/spek" }
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"

    testCompile "com.winterbe:expekt:0.5.0"
    testCompile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
    testCompile("org.jetbrains.spek:spek-api:1.1.2") {
        exclude group: "org.jetbrains.kotlin"
    }
    testRuntime("org.jetbrains.spek:spek-junit-platform-engine:1.1.2") {
        exclude group: "org.junit.platform"
        exclude group: "org.jetbrains.kotlin"
    }
}

Pada konfigurasi diatas, terdapat beberapa tambahan yaitu penulis menambahkan library test untuk kotlin yang disupport langsung dari jetbrains yaitu spekframework. Untuk fungsi assert, penulis menggunakan framework expekt.

Silahkan buat sebuah class App di dalam package org.rizki.mufrizal.belajarKotlin, silahkan sesuaikan dengan package anda, lalu masukkan codingan seperti berikut.

package org.rizki.mufrizal.belajarKotlin

import java.math.BigDecimal

/**
 * Created by rizkimufrizal on 6/3/17.
 */
class App {

    fun extensionMoney(extension: String, money: BigDecimal): String {
        return "$extension $money"
    }

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            val money = App().extensionMoney(extension = "Rp", money = BigDecimal(5000))
            println("saya mempunyai uang sebesar $money")
        }
    }
}

Berikut adalah beberapa penjelasan dari codingan diatas :

  • fun berfungsi untuk mendeklarasikan sebuah function / method pada kotlin. Jika anda tidak mendeklarasikan sebuah type data maka secara default method tersebut adalah berupa Unit atau void.
  • "$extension $money" adalah contoh dari string interpolation, sehingga yang memiliki tanda $ akan dieksekusi.
  • companion object sebagai static jika anda menggunakan bahasa pemrograman java.
  • @JvmStatic juga sebagai static, akan tetapi berbeda dengan companion object, dimana companion object hanya dapat diakses melalui instance, sedangkan jika menggunakan @JvmStatic maka anda dapat langsung memanggil suatu fungsi dari class nya langsung. Contoh penggunaan ini akan dibahas pada artikel selanjutnya.
  • val berfungsi untuk mendeklarasikan variabel yang bersifat immutable / jika object nya telah dibuat maka isi dari vaeriabel tersebut tidak dapat dirubah, sedangkan var kebalikan dari val yaitu bersifat mutable.
  • money adalah variabel dengan type data string. Mengapa type string ? karena return dari function extensionMoney adalah string. Tanpa mendeklarasikan type data, kotlin dapat dengan mudah menebak type data yang ada di dalam variabel money.

Untuk menjalankan codingan diatas, silahkan klik pada icon kotlin dibagian kiri, lalu pilih menu run seperti berikut.

Screen Shot 2017-06-03 at 11.30.48 PM.png

Oke, langkah selanjutnya kita akan melakukan test, silahkan buat sebuah file AppTest di dalam package test anda. Lalu masukkan codingan seperti berikut.

package org.rizki.mufrizal.belajarKotlin

import com.winterbe.expekt.should
import org.jetbrains.spek.api.Spek
import org.jetbrains.spek.api.dsl.given
import org.jetbrains.spek.api.dsl.it
import org.jetbrains.spek.api.dsl.on
import java.math.BigDecimal

/**
 * Created by rizkimufrizal on 6/3/17.
 */
class AppTest : Spek({
    given("a extension money") {
        val app = App()
        on("set extension and money") {
            val money = BigDecimal(7000)
            val extensionMoney = app.extensionMoney("Rp", money)
            it("should return extension and money") {
                extensionMoney.should.equal("Rp $money")
            }
        }
    }
})

Untuk menjalankan test diatas, silahkan akses project anda dengan terminal lalu jalankan perintah berikut.

gradle test

Jika berhasil maka akan muncul output seperti berikut.

:compileKotlin UP-TO-DATE
:compileJava NO-SOURCE
:copyMainKotlinClasses UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:compileTestKotlin
Using kotlin incremental compilation
:compileTestJava NO-SOURCE
:copyTestKotlinClasses UP-TO-DATE
:processTestResources NO-SOURCE
:testClasses UP-TO-DATE
:junitPlatformTest

Test run finished after 5066 ms
[         4 containers found      ]
[         0 containers skipped    ]
[         4 containers started    ]
[         0 containers aborted    ]
[         4 containers successful ]
[         0 containers failed     ]
[         1 tests found           ]
[         0 tests skipped         ]
[         1 tests started         ]
[         0 tests aborted         ]
[         1 tests successful      ]
[         0 tests failed          ]

:test SKIPPED

BUILD SUCCESSFUL

Total time: 9.272 secs

Sekian artikel mengenai setup project kotlin, jika ada saran dan komentar silahkan isi dibawah dan terima kasih :)