Git Eski Committen Branch Almak

Merhaba,

Elimizdeki projemizin eski halini ve aşamaları görmek ve eski halinden bir kopya alıp geliştirmek yapabilmek için bir örnek üzerinden gidelim.

master branchında çalışıyoruz.

git pull origin master 

Aşağıdaki komutu çalıştırdığınızda en üstteki commit karşısında (origin/master, origin/HEAD, master) yazdığını görebiliriz.

git tree

aşağıdaki komutu ile bütün commit leri ve ayrıntıları görüyoruz.

git log 

örnek olarak 4 adet commitimiz olsun

commit 4 {2021222324}
commit 3 {1516171819}
commit 2 {1011121314}
commit 1 {123456789}

Ben commit 2 den sonra hangi değişiklikler yapıldı ise onları görmek istemiyorum.

git fetch origin 

git fetch origin 1011121314

komutunu veriyorum.
Ardından

git checkout FETCH_HEAD

Aşağıdaki komuttan sonra commit 2 karşısında HEAD yazacaktır.
HEAD durumunu kontrol edelim.

git tree

Artık branch oluşturabiliriz

git checkout -b new_branch_name

 

Tagged with:
GIT kategorisinde yayınlandı

Plsql Notları

-- PLSQL HAKKINDA BILGILER --

-- ismi procedural language extension to structured query language nin kısalmasıdır.

-- Konu 1 --
-- herhangi bir ismi olmayan begin ile başlayıp end ile biten yapılardır
-- sql bir dil değil motordur. veri manipulasyonu yapılır.
-- plsql bir dildir. uygulamalar geliştirilir.
-- sql ifadelerimiz sql motoruna plsql ifadelerimiz plsql motoruna gönderilerek çalıştırılır.
-- bu blok çalıştıktan sonra hiç bir yerde saklanmaz.
-- plsql çıktısını görmek için aşağıdaki komutunu veriyoruz. 
SET serveroutput ON;  

-- çıktı gösteren bir block yazalım
BEGIN
	dbms_output.put_line('plsql e baslangic yaptik.');
END;


-- Konu 2 --
-- degisken tanımlama ve deger atamak
-- DECLARE kısmında değişken tanımlama yapılır.
-- := şeklinde deger atama yapıyoruz.
--
DECLARE
	l_emp_no NUMBER;  -- number da boyut vermek zorunlu değildir fakat verilebilir.  
	l_emp_name varchar2(50); -- varchar da boyut vermek zorundayız vermezsek otomatik boyutunu alır 4k
	l_emp_surname varchar2(30) DEFAULT 'STEVEN';  -- Oluştururken otomatik atama yapıldı.
	l_hire_date DATE DEFAULT sysdate; 
BEGIN
	dbms_output.put_line('-------');
	
	l_emp_no := 20;
	dbms_output.put_line(l_emp_no);  -- burada otomatik implicit converter çalıştır. to_char(l_emp_no) şeklinde yaptı.
	
	l_emp_name := 'DAVID';
 	dbms_output.put_line(l_emp_name);
 	
 	dbms_output.put_line(l_emp_surname);
 	
 	dbms_output.put_line(l_hire_date);
 	l_hire_date := TO_DATE('01.01.2018','dd.mm.yyyy');
 	dbms_output.put_line(l_hire_date);
END;

-- Konu 3 -- 
-- degisken isimlendirme standartı oluşturabiliririz.
-- l_emp_no     -- l lokal değişken 
-- lv_emp_name  -- l lokal , v varchar 
-- ld_hire_date -- l lokal , d date


-- Konu 4 --
-- Tablodaki alanların tipini bilmeden değişken oluşturmak
-- tablodaki alanın tipi ne ise değişkenin tipi otomatik o yapılmış oluyor.
-- Tablodaki alan tipleri var, degisken tipleri var. Bu ikisi aynı olabilir.
DECLARE
	ln_emp_no employees.employee_id%TYPE;
	ld_hire_date employees.hire_date%TYPE;
BEGIN
	dbms_output.put_line('----');
	ln_emp_no := 11;
	ld_hire_date := SYSDATE;

	dbms_output.put_line(ln_emp_no);
	dbms_output.put_line(ld_hire_date);
END;


-- Konu 5 --
-- anonymous block içinde block kullanımı
-- istenildigi kadar iç içe kullanılabilir.
DECLARE
	l_var_1 NUMBER DEFAULT 10;
	l_var_2 NUMBER DEFAULT 20;
	l_result NUMBER;
BEGIN
	dbms_output.put_line(' ----- ');
	l_result := l_var_1 * l_var_2;
	dbms_output.put_line(l_result);
	DECLARE
		l_var_3 NUMBER DEFAULT 30;
	BEGIN
		dbms_output.put_line(l_var_3);
	END ;

END isim_verdim_dis_blok;

-- Konu 6 --
-- into kullanımı
-- sorguların sonucunu alıp kullanmak için kullanırız
-- NOT 
-- plsql içinde sql çalıştırıldığında dönen değeri tutacak bir yer yoktur.
-- Bu nedenle dönen değeri bir değişkene veya bir collection a atmalıyız ki kullanabilelim.
-- deneyip hatayı alalım.
BEGIN
	SELECT * FROM DEPARTMENTS;
END;

-- Tek kayıt veya tek alan getiren sorguların sonucunu bir değişkene atayabiliyoruz.Çok kayıt gelirse hata alırız.
-- 

CREATE SEQUENCE testseq;

SELECT * FROM DEPARTMENTS;
DECLARE 
	dept_no DEPARTMENTS.department_id%TYPE;
BEGIN
	SELECT testseq.nextval 
		INTO dept_no
	FROM dual;
	
	dbms_output.put_line('---');
	dbms_output.put_line(dept_no);
END;

DECLARE
	v_1 NUMBER;
	v_2 NUMBER;
	v_3 NUMBER;
BEGIN
	SELECT 1,2,3
	INTO v_1,v_2,v_3
	FROM dual;

	dbms_output.put_line(v_1 ||'-'|| v_2 ||'-'||v_3 );
END;


-- Konu 9
-- kontrol yapıları
-- if elsif else
DECLARE
	ln_emp_count NUMBER ;
BEGIN
	
	SELECT count(*)
		INTO ln_emp_count
	FROM
	EMPLOYEES;
	
	IF  ln_emp_count < 20
		THEN
			dbms_output.put_line('20 den az çalısan var');
	ELSIF ln_emp_count BETWEEN 21 AND 50
		THEN
			dbms_output.put_line('20 ile 50 arasında çalışan var');
	ELSE
			dbms_output.put_line('50  den fazla çalışan var');
	END IF;
END;


-- konu 10
-- CASE WHEN yapısı
-- hem plsql de hemde sql de case when yapısı mevcut. 
-- sql de case when
SELECT e.employee_id,
  CASE e.first_name 
       WHEN 'Steven' THEN 'user is GOOD'
       WHEN 'Neena' THEN 'user is BAD..'
       WHEN 'Lex' THEN 'user is AWESOME..'
       ELSE 'user UNKNOWN'
  END case_kolonu
FROM EMPLOYEES e ORDER BY e.EMPLOYEE_ID;
-- sql de decode
-- sadece sql de kullanıllr plsql de kullanılmaz. case when daha hızlı ve performanslıdır.
-- sadece eşitir işlemi yapılabilir ,büyük küçük gibi karşılaştırmalar yapılamaz.
SELECT e.employee_id,
  DECODE( e.first_name ,
        'Steven' , 'user is GOOD' ,
       	 'Neena' , 'user is BAD..' , 
       	 'Lex' , 'user is AWESOME..',
       	 'user UNKNOWN' ) case_kolonu
FROM EMPLOYEES e ORDER BY e.EMPLOYEE_ID;
-- plsql de case when
DECLARE
	ln_job_count NUMBER ;
	lv_result varchar(50);
BEGIN
	
	SELECT count(*)
		INTO ln_job_count
	FROM JOBS;
	
	
	lv_result := CASE  
					WHEN ln_job_count = 4 AND  ln_job_count <= 10--BETWEEN 4 AND 10	
						THEN '4 ile 10 tane iş var'
					ELSE '10  den fazla iş var'
				END;
	dbms_output.put_line(lv_result);
END;


-- konu 11
-- bir tavsiye loop içine insert update delete yazmaktan, fonksiyon çağırmaktan olabildiğince kaçmalıyız :)
-- peki kullanmaktan kaçamadım o zaman ise döngü bir kere çalışacak şekilde tasarlamalıyız.
--- döngü içinde döngü zaten hiç kullanmayın. 
-- bir veriyi doldurmak istiyorsak mutlaka sql ile doldurmalıyız loop ile döngü doldurulursa performans kaybıdır.
-- döngüler
	-- loop konusu (TERCIH EDILEN)
	-- programlamada do..while gibi çalışır.
	-- loop içinde sql yazılmaz... yazılabilir fakat best practice değildir.
DECLARE
	ln_result NUMBER DEFAULT 0;
BEGIN
	LOOP
			ln_result := ln_result + 1;
			BEGIN
				dbms_output.put_line(TO_CHAR(ln_result));
			END;
			
		EXIT WHEN ln_result = 5; -- loop tan çıkmak için kural
	END LOOP;
END;
	-- while..loop konusu (EN AZ TERCIH EDILEN)
	-- programlamada while gibi çalışır.

DECLARE
	ln_result NUMBER DEFAULT 0;
BEGIN
	WHILE ln_result > ' || SQL%ROWCOUNT);
	END IF;

	
	lb_cursor_status :=	SQL%ISOPEN;
	
	IF  sql%FOUND = lb_cursor_status
		THEN
			dbms_output.put_line('CURSOR ACIK');
	ELSIF sql%NOTFOUND = lb_cursor_status
		THEN
			dbms_output.put_line('CURSOR KAPALI');
	END IF;

END;

 --Explicit Cursor
 
 -- implicit cursor kullanmak istemeyip kendimiz de cursor tanımlıyabiliyoruz.
 		-- Çıktı olarak sadece bir satır veri alabildik.
		-- Çünkü cursor bir satırı temsil edebiliyordu :)
 DECLARE
 	CURSOR my_cursor
 	IS
 		SELECT * FROM DEPARTMENTS ORDER BY DEPARTMENT_ID DESC;
 	
 	dept_rec departments%ROWTYPE;
 
 BEGIN 
	 OPEN my_cursor;
			FETCH my_cursor INTO dept_rec;
			dbms_output.put_line(dept_rec.department_name);  
	 CLOSE my_cursor;
 END;

-- cursor açık mı kapalı mı öğrenelim.
 DECLARE
 	CURSOR my_cursor
 	IS
 		SELECT * FROM DEPARTMENTS ORDER BY DEPARTMENT_ID DESC;
 	
 	dept_rec departments%ROWTYPE;
 
 	lb_cursor_status BOOLEAN;
 BEGIN 
	 
			lb_cursor_status :=	my_cursor%ISOPEN;
			 
		 	IF  lb_cursor_status
				THEN
					dbms_output.put_line('KONTROL 1 - CURSOR ACIK');
			ELSE 
					dbms_output.put_line('KONTROL 1 - CURSOR KAPALI');
			END IF;
	 	
	 OPEN my_cursor;
					
					lb_cursor_status :=	my_cursor%ISOPEN;
	
					IF  lb_cursor_status
						THEN
							dbms_output.put_line('KONTROL 2 - CURSOR ACIK');
					ELSE
							dbms_output.put_line('KONTROL 2 - CURSOR KAPALI');
					END IF;
		
	FETCH my_cursor INTO dept_rec;
		
					lb_cursor_status :=	my_cursor%ISOPEN;
	
					IF  lb_cursor_status
						THEN
							dbms_output.put_line('KONTROL 3 - CURSOR ACIK');
					ELSE
							dbms_output.put_line('KONTROL 3 - CURSOR KAPALI');
					END IF;
				
	 dbms_output.put_line(dept_rec.department_name);
		
	 CLOSE my_cursor;
	
					lb_cursor_status :=	my_cursor%ISOPEN;
	
					IF  lb_cursor_status
						THEN
							dbms_output.put_line('KONTROL 4 - CURSOR ACIK');
					ELSE
							dbms_output.put_line('KONTROL 4 - CURSOR KAPALI');
					END IF;
 END;

		

 
 -- cursor dan tüm tablodaki veriyi alabilmek.
 -- loop
 DECLARE
 	CURSOR my_cursor
 	IS
 		SELECT * FROM DEPARTMENTS ORDER BY DEPARTMENT_ID DESC;
 	
 	dept_rec departments%ROWTYPE; -- departments tablosundaki bir satıra karşılık gelen record tanımladık.
 
 BEGIN
	 OPEN my_cursor;
		LOOP	
			FETCH my_cursor INTO dept_rec;
		
			dbms_output.put_line(dept_rec.department_name);
			dbms_output.put_line(my_cursor%ROWCOUNT); --cursorun şuan kaçıncı elemanındayım.
			EXIT WHEN my_cursor%NOTFOUND; -- cursor da eleman kalmadığında otomatik loop dan çıkış yapıyoruz.
		END LOOP;
	 CLOSE my_cursor;
 END;
 
-- cursor dan tüm tablodaki veriyi alabilmek. (CURSOR HIZLI KULLANIM)
-- FOR
-- FETCH yok, OPEN yok , CLOSE yok 
DECLARE
 	CURSOR my_cursor
 	IS
 		SELECT * FROM DEPARTMENTS ORDER BY DEPARTMENT_ID DESC;
 
 BEGIN
	 FOR i_record IN my_cursor  -- oracle tarafından otomatik %ROWTYPE record oluşturulmuş olunur. 
	 LOOP
	 	dbms_output.put_line(i_record.department_name);
	 END LOOP;
 END;
 
-- cursor a parametre göndermek.
-- cursor kullanıldığında sadece sorgulanmış veriler doludur.
DECLARE
	CURSOR my_cursor(p_location_id number)
	IS
 		SELECT * FROM DEPARTMENTS
 		WHERE LOCATION_ID = p_location_id
 		ORDER BY DEPARTMENT_ID DESC;
BEGIN
	 FOR i_record IN my_cursor(1700) -- örnek olması için parametreyi elimle verdim. 
	 LOOP
	 	dbms_output.put_line(i_record.department_name);
	 END LOOP;
END;

-- select for update
-- tabloyu değil sadece kayıtları kilitler
SELECT * FROM DEPARTMENTS FOR UPDATE;--WAIT 5  bekle
									 -- NOWAIT; bekleme


-- cursor where current of kullanımı
DECLARE
	CURSOR cur_department(p_location_id number)
	IS
 		SELECT * FROM DEPARTMENTS
 		WHERE LOCATION_ID = p_location_id
 		ORDER BY DEPARTMENT_ID DESC;
BEGIN
	 FOR i_rec IN cur_department(10) -- örnek olması için para etreyi elimle verdim.  
	 LOOP
		UPDATE DEPARTMENTS
		SET DEPARTMENT_NAME = 'DEPT_NAME_' || i_rec.department_id
		WHERE CURRENT OF cur_department; -- o cursor da bu update işlemini çalıştır. Eski bir kullanım artık tercih edilmiyor. 
	 END LOOP;
END;





-- Ref Cursor
-- anlat
-- open fetch close yapmak zorundayız.
--- sys_refcursor https://stackoverflow.com/questions/18274258/cursor-for-loop-in-oracle

--- best practice kayıt bulundu bulunmadı diye SQL%notfound kullanılmaz. kayıt bulamazsa exceptiona düşyor
-- ordan sqlfound yapıyoruz. 


-- Bulk Collect Konusu
-- ForALL konusu -- for loop yaptıktan sonra tek tek kayıtları update etmek isteiğimizde, tek seferde kayıtlara ulaşıp yapabiliriz.
-- araştır.
-- https://www.guru99.com/pl-sql-bulk-collect.html


-- sqlj nedir ?
-- araştır
-- pre compiler kavramı
-- java içine sql yazılamıyormuş sqlj içine java yazıyorsunuz plsql yazıyorsunuz sqlj ile compile edince bize java kodunu export ediyormuş
-- proC
-- proFortran
-- proCobol



-- konu 15
-- exceptions

-- anonymous block içerisindeki iş mantığında bir hata oldu. Bu hatayı yakaladık ve konsola çıktı olarak verdik.
-- exception kısmını yazmadığımız zaman ki halini deyenip görebilirsiniz :)
DECLARE
	l_emp varchar2(100);
BEGIN
	SELECT first_name || ' '|| last_name
		INTO l_emp
	FROM employees
	WHERE employee_id = 5000; -- olmayan bir kayıt çağırdım

	dbms_output.put_line(l_emp);

	EXCEPTION 
		WHEN NO_DATA_FOUND 
			THEN 
				dbms_output.put_line(' HATA -- Boyle bir employee kaydı yok');
END;


-- bir insert atalım ve oluşan hatayı yakalayalım.
-- burada bir problem var. KONTROL 2 kısmından önce bir hata oluştu.
	-- bu nedenle anonymous block içindeki KONTROL 2 kısmı beklediğimiz gibi çalışmadı.
DECLARE
	l_emp varchar2(100);
BEGIN
	SELECT first_name || ' '|| last_name
		INTO l_emp
	FROM employees
	WHERE employee_id = 100; -- olan bir kayıt çağırdım.

	dbms_output.put_line(l_emp);
	dbms_output.put_line('KONTROL 1');

	INSERT INTO departments VALUES(10,'bolum 10',100,1700);  
	
	dbms_output.put_line('KONTROL 2'); -- buradaki kod önceki satırda kırıldı. bu satır yazılamadı.

	EXCEPTION 
		WHEN NO_DATA_FOUND 
			THEN 
				dbms_output.put_line(' HATA -- Boyle bir employee kaydı yok');
		WHEN DUP_VAL_ON_INDEX
			THEN
				dbms_output.put_line(' HATA -- boyle bir department kaydı var girilemez');

END;


-- iç içe anonymous block kullanarak bir önceki problemi çözmüyoruz fakat kodun kırılmasını engelliyebiliyoruz.
-- KONTROL 3 bölümü çalıştırılabiliyor. Çünkü iç içe anonymous block kullandık.
DECLARE
	l_emp varchar2(100);
BEGIN
	
	BEGIN
		SELECT first_name || ' '|| last_name
			INTO l_emp
		FROM employees
		WHERE employee_id = 100; -- olan bir kayıt çağırdım.
		
		dbms_output.put_line(l_emp);
		dbms_output.put_line('KONTROL 1');
		EXCEPTION 
				WHEN NO_DATA_FOUND 
					THEN 
						dbms_output.put_line(' HATA -- Boyle bir employee kaydı yok');
	END;
	BEGIN
		INSERT INTO departments VALUES(10,'bolum 10',100,1700);  
		
		dbms_output.put_line('KONTROL 2'); -- buradaki kod önceki satırda kırıldı. bu satır yazılamadı.
		EXCEPTION 	
			WHEN DUP_VAL_ON_INDEX
				THEN
					dbms_output.put_line(' HATA -- boyle bir department kaydı var girilemez');
	END;

	dbms_output.put_line('KONTROL 3'); -- buradaki kod yazılabildi.

END;

---- iç içe anonymous block larda exception kullanımı
-- 
-- bir anonymous block içerisinde bir oluşan hata,
--  o blok içinde yazılmış hatalardan biri değil ise 
-- kendisinden bir üst katmandaki anonymous block içerisinde aramaya başlar.
-- eger bulamaz ise yine bir üstekine bakar.
-- Burada dikkat edilmesi gereken kısım şudur. Bir üsteki bloğa kendi bloğunun end kısmından 
-- sonra gelen kısmı çalıştıracak şekilde gitmez. Direkt olarak exception bölümüne gider.
-- burada bir iş mantığınız var ise bu atlanmış olur.
-- exception bölümünde yakalandıktan sonra kod kaldığı yerden akışına devam eder.
-- çıktı şu şekildedir.  5. ve 6. satır atlanmıştır. :)  
		--1
		--2
		--3
		--4
		-- HATA -- Boyle bir employee kaydı yok
		--7

DECLARE
	l_emp varchar2(100);
BEGIN
	dbms_output.put_line('1');
	BEGIN
		dbms_output.put_line('2');
		BEGIN
			dbms_output.put_line('3');
			BEGIN
				dbms_output.put_line('4');
			
				SELECT first_name || ' '|| last_name
					INTO l_emp
				FROM employees
				WHERE employee_id = 5000; -- olmayan bir kayıt çağırdım.
				--WHERE employee_id = 100; -- olan bir kayıt çağırdım.
				
				dbms_output.put_line(l_emp);
			
				EXCEPTION 
				WHEN TOO_MANY_ROWS 
					THEN 
						dbms_output.put_line(' HATA -- Birden fazla kayıt geldi.');

			END block_four;
			dbms_output.put_line('5');
		END block_three;
		dbms_output.put_line('6');
		EXCEPTION 
			WHEN NO_DATA_FOUND 
				THEN 
					dbms_output.put_line(' HATA -- Boyle bir employee kaydı yok');
	END block_two;
	dbms_output.put_line('7');
END;

--- exception raise kullanımı
-- bu kullanım ile kodun akışını istediğimizde kırarız. 
-- beklediğim bir istisna durumunu kendim oluşturmuş oluyorum.
-- programada throw Exception(); gibi.

-- hatayı yakaladıktan sonra uygulamamız kaldığı yerden devam etsin 

DECLARE
	l_emp_count NUMBER;
	e_emp_count EXCEPTION;
BEGIN 
	BEGIN
		SELECT count(*)
			INTO l_emp_count
		FROM EMPLOYEES;
	
		dbms_output.put_line(l_emp_count);
	
		IF( l_emp_count > 100 ) 
		THEN 
			RAISE e_emp_count;
		END IF;
	
		dbms_output.put_line('Bu satir istisna firlatiğimiz için çalışmıyor.');
		
		EXCEPTION
			WHEN e_emp_count
				THEN dbms_output.put_line('e_emp_count istisnasına düstü');
	
		dbms_output.put_line('Bu satir istisna EXCEPTION bölümüne girdiği için çalışıyor.');
	END;
	dbms_output.put_line('En dışarıdaki anonymous block Bu satir istisna EXCEPTION bölümüne girdiği için çalışıyor.');
END;


-- hatayı yakaladıktan sonra birşey yapıp sonra tekrar hata fırlatılabilir.

DECLARE
	l_emp_count NUMBER;
	e_emp_count EXCEPTION;
BEGIN 
	BEGIN
		SELECT count(*)
			INTO l_emp_count
		FROM EMPLOYEES;
	
		dbms_output.put_line(l_emp_count);
	
		IF( l_emp_count > 100 ) 
		THEN 
			RAISE e_emp_count;
		END IF;
	
		dbms_output.put_line('Bu satir istisna firlatiğimiz için çalışmıyor.');
		
		EXCEPTION
			WHEN e_emp_count
				THEN dbms_output.put_line('e_emp_count istisnasına düstü');
				RAISE NO_DATA_FOUND; -- RAISE NO_DATA_FOUND; bu tipte bir üste fırlatır.
			
		dbms_output.put_line('Bu satir istisna EXCEPTION bölümünde RAISE; olduğundan çalışmıyor.');
	END;
	dbms_output.put_line('En dışarıdaki anonymous block Bu satir istisna EXCEPTION bölümünde RAISE; olduğundan çalışmıyor.');

	EXCEPTION
		WHEN NO_DATA_FOUND
			THEN dbms_output.put_line('Iceriden RAISE NO_DATA_FOUND seklinde fırlatıldıgi icin burası çalışıyor.');
END;



-- kodun akışını kırmak ve programın o hata sonrasında durmasını istiyorum. 
-- iç içe olan anonymous block ların içlerinde
--  exception when then mekanizması yazmak yerine en dıştakine hepsini yakalayabiliriz.


-- exception pragma
-- oluşmasını beklediğimiz bir istisnanın istediğimz bir hata kodu ile eşleştirilmesidir.
-- PRAGMA EXCEPTION_INIT ile oluşturuyoruz.
-- hatayı yakaladıktan sonra uygulamamız kaldığı yerden devam ediyor.
DECLARE
	e_ora_60 EXCEPTION;
	PRAGMA EXCEPTION_INIT (e_ora_60,-1400) ; -- e_ora_60 hatası oluştuğunda bu hata kodunu bas
BEGIN
		BEGIN
			INSERT INTO departments (department_id,department_name,manager_id,location_id)
			VALUES (260,NULL,NULL,NULL);
		
			EXCEPTION	
				WHEN e_ora_60
					THEN
						dbms_output.put_line('e_ora_60 BEKLEDIGIM HATA OLUSTUGUNDA BURAYA GIRER');
						dbms_output.put_line('SQLCODE -->> '|| SQLCODE || ' SQLERR -->> '|| SQLERRM || ' HATASI OLUSTU');
				WHEN OTHERS
					THEN -- when others kullanmamak en güzeli. eğer iç blocklarda bir yazarsa kod çalıştı zannedersin ama biri o hatayı yutmuş olur :)
						dbms_output.put_line('BASKA HATA OLUSTUGUNDA BURAYA GIRER');
						dbms_output.put_line('SQLCODE -->> '|| SQLCODE || ' SQLERR -->> '|| SQLERRM || ' HATASI OLUSTU');
		-- ÇIKTISI		
		--	e_ora_60 BEKLEDIGIM HATA OLUSTUGUNDA BURAYA GIRER
		--	SQLCODE -->> -1400 SQLERR -->> ORA-01400: cannot insert NULL into ("HR"."DEPARTMENTS"."DEPARTMENT_NAME") HATASI OLUSTU
		END;
		dbms_output.put_line('HATA OLUSTUKTAN SONRA YAKALANDI VE BURADAN DEVAM ETTI ');
END;

--
-- raise application error
-- PRAGMA EXCEPTION_INIT ile var olan bir kodu vermek istediğimiz isim ile eşleştiriyorduk.
-- Fakat burada belirlediğimiz hata mesajlarını oracle tarafından
--  belirlenen -20000 ile -21000 arasınaki sayılarına atama yaparak kullanabiliriz.
-- anonymous block içinden bu bloğu çağıran uygulamaya hata dönülmesi sağlanır. 
DECLARE
	l_test_no NUMBER DEFAULT 10;
BEGIN
	IF l_test_no > '|| SQLERRM);
-- çıktı			
--	-20008 ->> ORA-20008: l_test_no 11 den kücüktür.
END;





-- konu 16
-- ROLLBACK example ekle
-- 
-- konu 17 ve konu 18
-- fonksiyonlar ve prosedürler subprograms olarak değerlendirilirler
-- fonksiyonlar ve prosedürler anonymous block ların isim verilmiş halleri olarak karşımıza çıkar.
-- biraz karşılaştırma yapalım.
-- anonymous block 
	-- isimsiz plsql bloklarıdır.
	-- her çalıştırıldığında yeniden derlenir.
	-- veritabanında saklanmaz.
	-- diğer uygulamalardan çağırılamaz.
	-- değer dönemezler
	-- parametre alamazlar. 
-- fakat
-- subprograms (functions , procedures)
	-- isimlendirilmişlerdir.
	-- bir kez derlendikten sonra çalışmaya hazır.
	-- veritabanında saklanır.
	-- diğer uygulamalardan çağrılabilir.
	-- fonksiyon tipi değer dönmek zorundadır.
	-- parametre alabilirler
	
-- konu 17
-- functions 
-- function kullanırken insert update delete yazmamak lazım bu işlemleri procedure de yapmaliyiz.

CREATE OR REPLACE FUNCTION f_get_employee_info(p_employee_id IN NUMBER)
	RETURN VARCHAR2
	IS

	l_emp_info VARCHAR2 (1000);
BEGIN
	SELECT first_name ||'*'|| last_name
		INTO l_emp_info
	FROM EMPLOYEES
	WHERE employee_id = p_employee_id;

	RETURN l_emp_info;

	EXCEPTION
		WHEN NO_DATA_FOUND
			THEN
				l_emp_info := 'NOT_FOUND EMPLOYEE';
				RETURN l_emp_info;
END;
--
SELECT 	*
FROM user_objects
WHERE
	object_name
LIKE '%f_get_employee_info%';
--
DECLARE
	l_result_info varchar2(20);
BEGIN
	SELECT f_get_employee_info(1) 
		INTO l_result_info
	FROM dual	;

	dbms_output.put_line(l_result_info);

	l_result_info := f_get_employee_info(100);

	dbms_output.put_line(l_result_info);

END;

-- function in,out,in-out params

-- plsql8 -- 40.06 dk

Veritabanı kategorisinde yayınlandı

motd dosyası

Merhabalar,

motd dosyası ,
bir linux dağıtımında terminali açtığımızda hemen yukarıda bulunan yazıların bulunduğu dosyadır.

Dosya ismi message of the day cümlesinin baş harflerinden gelmektedir.

Dosyanın işletim sistemi üzerinde nerede bulunduğunu öğrenelim.
Ben sistem olarak Debian dağıtımını kullanacağım.

$ vi /etc/motd
The programs include with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

Biraz değiştirelim.

 

 Çok güzel bir dosya

The programs include with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

kaydedip kapatalım.

tekrar açtığımızda sonucu göreceğiz.

Iyi günler, Iyi Çalışmalar 🙂

Tagged with: , , , , ,
Linux kategorisinde yayınlandı

Vagrant Nedir

Değiştirilemez yapılar kurmak bizi bir çok dertten kurtara bilir mi ?

Yazılım geliştiriciler kodlarını yazar. Kendi ortamlarında test ederler.
Ardından bu kodu biri veya birileri test ederler. Ve genel de bizde çalışan
onlarda çalışmaz 🙂

Bu gibi durumların çok olası olduğu aşikardır.
Bu tarz durumları ortadan kaldırabilmek için iki kişinin de
test ortamı fiziksel olarak olmasa bile yazılımsal ve mantıksal
olarak aynı ortamlar yapabiliriz. Nasıl mı ?

Bir kutu düşünün ve kutu içerisine yazılımcıların geliştirmeleri mevcut.
Eğer test edecek kişiye de aynı kutunun tam bir kopyasını sunabilseydik
ve hatta canlı ortamda bile bu kutunun bir kopyasını kullanabilseydik
ne kadar güzel olurdu bir düşünelim ?

Değiştirilemez yapılar(immutable infrastructure) kurmak bize
istediğimiz bir an,
istediğimiz bir yerde,
istediğimiz bir versiyondaki kodu çalıştırabilmemize olanak sağlıyor.

A ve B versiyonlarına sahip kodlarımızı ayrı ayrı sanal makinalar
içerisine koyduğumuzu düşünelim. Önlerinde de bir yük dengeleyici (load balancer)
olsun.
Gelen istek trafiğini A yerine yeni versiyon olan B ye yönlendirelim. İşte en güzel an. İstediğimizi an trafiği A ya tekrar yönlendirebiliriz çünkü önceki alt yapımız yani A hala
hala elimizde mevcut olduğundan geri dönülebilirliği garantilemiş olduk.
Bu aracın asıl amacı canlı ortamda kullanılmak değil geliştirme ve test ortamlarında kullanmak içindir.

Herşey güzel birazcık terimlerden bahsedelim.

Türkçe de Vagrant kelimesi Göçebe olarak anlandırılıyor.

Peki amaç nedir ? Vagrant geliştirme ortamının sanallaştırılaması için gereken ayarları tutup, standart hale getirip kullanıyoruz. Tek bir dosya yardımı ile kurulum yapılan işleri ortak noktada toplayarak aynı ayar kümesi ile istenildiğinde oluşturabiliyor.
Ekibe yeni birisi katıldı. Sadece bu ayar dosyasına erişerek tüm geliştirme ortamını kurabilir.

Peki bu ürünü neden öğrenelim ki ?

Aslında burada vagrant ile yapılan tüm adımları kendimiz de yapabiliriz. Zaten işlerin hepsini aradaki hypervisor  yani sanal makinaların işletim sistemi üzerinde çalıştırılabilmesini sağlayan yapı sağlıyor.
Fakat herkes aynı işi yaparken aynı şekilde yapmayabilir. Vagrant tüm işlerin ortak bir konfigürasyon dosyası ile yönetilmesine olanak sağlıyor.

 

 

Uygulamanın sitesini gidip bilgisayarımıza kurabiliriz.

https://www.vagrantup.com

Tabi vagrant kullanabilmek için bir sanallaştırma aracı (hypervisor)
kullanmak gerekiyor. VMware Server,VirtualBox vb.

Uygulamanın sitesini gidip bilgisayarımıza kurabiliriz.

https://www.virtualbox.org

Örneğimizi açıklayalım.
Bir işletim sistemi kurup içerisine java yükleme adımlarını otomatikleştireceğiz.

Siz bu durumu istediğiniz kadar genişletebilirsiniz.(git yüklemek,kodu çekmek,geliştirici
araçlarını yüklemek eclipse,phpstorm vb. winrar benzeri araçlar kurmak vb. )

Hazır imajları bulabileceğimiz vagrant bize sağladığı bir site mevcut. Bir çok kişinin
hazırladığı bu tarz ortamlardan birini indirip kullabiliriz.

https://vagrantcloud.com

Ve ya biz kendimiz yapıp oraya koyup daha sonra kullanabiliriz.

https://www.vagrantup.com/docs/vagrant-cloud/api.html#create-a-box

Ben hazır bir imaj üzerinden ilerleyeceğim.
İşletim sistemi olarak Alpine kullanacağım.

https://app.vagrantup.com/alpine/boxes/alpine64

Hemen çalışma ortamımıza gidelim.

$ /home/user/workarea

$ mkdir vagrant-alpine64

$ cd vagrant-alpine64/
$ vagrant init alpine/alpine64

A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Şuan sadece ayarların bulunduğu bir dosya indirmiş olduk hemen bakalım.

$ ls
Vagrantfile

Dosya içeriğine bakalım.

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.

# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "alpine/alpine64"

# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# config.vm.network "forwarded_port", guest: 80, host: 8080

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"

# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"

# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"

# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.

# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.

config.vm.provision "shell", inline: <<-SHELL
    #   apt-get update
    #   apt-get install -y apache2
     apk add git
     SHELL
end

Bu dosyaya ek olarak işletim sistemi kurulumundan sonra git uygulamasının
kurulu gelmesini istediğimden şu komutu ekliyorum.

Işletim sisteminin paket yöneticisine uygun olacak şekilde eklememi yapıyorum.
Burada apk kullanılıyor.

apk add git

Eklemelerimizi yaptıktan sonra

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'alpine/alpine64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'alpine/alpine64' is up to date...
==> default: Setting the name of the VM: vagrant-alpine64_default_1544821894284_52624
==> default: Vagrant has detected a configuration issue which exposes a
==> default: vulnerability with the installed version of VirtualBox. The
==> default: current guest is configured to use an E1000 NIC type for a
==> default: network adapter which is vulnerable in this version of VirtualBox.
==> default: Ensure the guest is trusted to use this configuration or update
==> default: the NIC type using one of the methods below:
==> default: 
==> default:   https://www.vagrantup.com/docs/virtualbox/configuration.html#default-nic-type
==> default:   https://www.vagrantup.com/docs/virtualbox/networking.html#virtualbox-nic-type
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Connection reset. Retrying...
    default: Warning: Remote connection disconnect. Retrying...
    default: 
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default: 
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default: 
    default: Guest Additions Version: 5.1.30 r118389
    default: VirtualBox Version: 5.2
==> default: Mounting shared folders...
    default: /vagrant => /workarea/vagrant-alpine64
==> default: Running provisioner: shell...
    default: Running: inline script
    default: fetch http://nl.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
    default: fetch http://nl.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz
    default: fetch http://nl.alpinelinux.org/alpine/edge/community/x86_64/APKINDEX.tar.gz
    default: (1/9) Installing libcrypto1.1 (1.1.1a-r0)
    default: -2.6.4-r0.
    default: (2/9) Installing ca-certificates (20180924-r1)
    default: (3/9) Installing nghttp2-libs (1.34.0-r0)
    default: (4/9) Installing libssh2 (1.8.0-r4)
    default: (5/9) Installing libssl1.1 (1.1.1a-r0)
    default: (6/9) Installing libcurl (7.62.0-r2)
    default: (7/9) Installing expat (2.2.6-r0)
    default: (8/9) Installing pcre2 (10.32-r0)
    default: (9/9) Installing git (2.19.2-r0)
    default: Executing busybox-1.27.2-r8.trigger
    default: Executing ca-certificates-20180924-r1.trigger
    default: 1 error; 130 MiB in 60 packages
The SSH command responded with a non-zero exit status. Vagrant
assumes that this means the command failed. The output for this command
should be in the log above. Please read the output to determine what
went wrong.


Virtual Box uygulamasını açarsak sanal makinanın çalışır durumda olduğunu göreceğiz.

Kullanıcı adımızı log lardan görebiliriz.

 username vagrant

Ardından terminali açıp git uygulamasının yüklendiğini kontrol ediyoruz.

git version

yazıyoruz. Uygulamamızın yüklendiğini görüyoruz.  Artık kullanıma hazırdır.

Biraz diğer komutlara değinelim.

Sanal makinamızın durumunu öğrenmek için

$ vagrant status

Kendi bilgisarımızdan sanal makinaya terminal üzerinden erişmek için

$ vagrant ssh

Terminalden sanal makinamızı kapatmak için

$ vagrant halt --force

Var olan sanal işletim sistemine bir şey yüklemek için tabi ki sanal makine içindeki kendi terminalini kullanabiliriz. Fakat burada işi vagrant tarafından yönetmek istiyoruz.

git için yapılanlara benzer şekilde yapabiliriz. Artından aşağıdaki komutu çalıştırmalıyız.

$ vagrant provision
$ vagrant up

Teşekkürler, Iyi çalışmalar 🙂

Devops kategorisinde yayınlandı

Continuous Integration ve Continuous Delivery için JSF, Git, Github, Travis-CI ve Heroku kullanalım

wordcloud
Bu yazımızda basit bir java web projesi geliştirerek uygulamamızın kullanıcılar ile buluşmasını otomatize edeceğiz.

Uygulamamızı geliştirirken Java Server Faces çatısını kullanacağız.
Uygulamamızın kodlarını Git yardımıyla Github üzerinde bulunacak.

Proje temel iskeletini ve bağımlılıklarını yönetmek için Apache Maven ,
projemizi derleyebilmek, varsa yazdığımız testleri koşturmak  ve hatta varsa bize hatalarmızı bildirmesi için continuous integration araçlarından Travis-CI kullacağız.

Uygulamamızı canlı olarak bir sunucuda koştuğunu görmek için Jetty  nin bir pluginini kullanarak  platform as a service(PaaS) ürünlerinden Heroku kullanacağız.

Terminalimizi açıyoruz.
Çalışma alanımıza giderek uygulamamızı bilgisayarımıza indirelim.

/home/user/workarea

 

Projemizin temel iskeletini maven aracı ile daha önceden oluşturup Github üzerinden yayınladım.

mvn archetype:generate -DgroupId=com.keramiozsoy.baseapp -DartifactId=baseapp -Dversion=0.0.1-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

Github üzerinde projemizi çekelim.

git clone https://github.com/keramiozsoy/jsf-travis-ci-heroku.git

Jsf projesi olması için yapılan değişiklikleri görmek için terminal üzerinden  komutu çalıştırabilirsiniz.

git checkout tags/v0.0.1

Projemizin maven üzerinde çoklu modül olarak davranabilmesini sağlayan değişiklikleri görmek için terminal üzerinden komutu çalıştırabilirsiniz.

git checkout tags/v0.0.2

Travis-CI ile projemizi ilişkilendirmek  için bazı eklemeler yapmalıyız. Aşağıdaki linklere göz atabilirsiniz.

https://travis-ci.org (ücretsiz)(açık depo)
https://travis-ci.com (ücretli)(kişiye özel depo)

 

Travis-CI a üye olup github hesabımızla ilişki kuruyoruz.

travisci-1

 

Travis bize .travis.yml isimli bir dosyayı projemize eklediğimizde yardımcı oluyor.  Bu dosya içerisine şu değerleri yazabiliyoruz.

  • Projem hangi dil ile yazılmıştır ?
  • Projem hangi java jdk versiyonu ile derleme yapılsın ?
  • Projem çalıştırılmadan önce bir sisteme hangi dosyalar yüklenmesi gereklidir ?
  • Projemdeki hangi testler çalıştırılsın ?
  • Projem Travis-CI  ile derlendikten sonra hangi sunucuya deploy yapılsın ?

Yukarıdaki soruları arttırmak tabi ki mümkün. Projemize ekleyeceğimiz dosya şu şekildedir.

.travis.yml

language: java

jdk: 
- oraclejdk8
- openjdk8

cache:
  directories:
    - '$HOME/.m2/repository'

before_script:
 - echo $HOME
 - echo $JAVA_OPTS
 - echo $MAVEN_OPTS

script: pwd && ls -al && mvn clean package

 

Yaptığımız değişiklikleri github adresimize gönderdiğimizde otomatik olarak uygulamamız değişiklikleri algılayarak çalışmaya başlayacak.

Fakat .travis.yml dosyasının gönderildiği adımdan sonra yapılan adımlarda bu işlem başlayacaktır.

travisci-2

Resimdeki adımlar görüldükten sonra  Travis-CI sunucuda çalıştırılabilecek hazır bir war dosyamız oluştu.

Uygulamamızı yayınlamak için Heroku ya üye olmalıyız.

https://www.heroku.com

Heroku üzerinde bir proje oluşturalım.

travisci-3
Uygulamamızı oluşturduktan sonra

  1.  Deployment Method bölümünden Github seçip ilişkilendirmek istediğimiz   uygulamayı seçiyoruz.
  2.  Automatic deploys bölümünden Wait for CI to pass before deploy  alanını Travis-CI üzerinden işlemleri yönetmek istediğimizden işaretliyoruz.              Enable Automatic Deploys bölümüne tıklıyoruz.
  3.  Projemizin Settings / Buildpacks bölümünden Add Buildpack ile Java seçip kaydediyoruz.
  4.  Son olarak Account Settings bölümündeki Api Key bölümündeki şifreyi daha sonra kullacağız.

Heroku tarafındaki ayarlarımız yaptık.

Travis-CI  daki projemizin more options/settings altında Environment Variables bölümünde bir değişken oluşturalım. Şifre kısmına ise Heroku üzerindeki Api Key değerini ekleyelim.
Benim oluşturduğum değişken şu isimdedir.

HEROKU_AUTH_TOKEN

 

Geliştirdiğmiz projemizin Heroku ya, Travis-CI tarafından tetiklenmesi için projemize gereken eklemeleri yapalım.

.travis.yml

deploy:
  provider: heroku
  api_key: 
    secure: $HEROKU_AUTH_TOKEN
  skip_cleanup: true
  app: jsf-travis-ci-heroku  ##heroku üzerindeki proje adı
  on:
    branch: master

 

Jetty isimli web-sunucusunun jetty-runner isimli plugini ile jar uzantılı dosyalarımızı ekstra kurulum yapmadan ayağa kaldırabiliyoruz. Hemen gerekli eklemeleri projemizde yapalım.

pom.xml

Build etiketlerinin içine eklemelerimizi yapıyoruz.

  
 <build>
 <finalName>baseappparent</finalName>
   <plugins>
      <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-dependency-plugin</artifactId>
       <version>2.4</version>
       <executions>
         <execution>
             <phase>package</phase>
             <goals><goal>copy</goal></goals>
             <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>org.eclipse.jetty</groupId>
                  <artifactId>jetty-runner</artifactId>
                  <version>9.4.9.v20180320</version>
                  <destFileName>jetty-runner.jar</destFileName>
                </artifactItem>
              </artifactItems>
             </configuration>
          </execution>
         </executions>
 </plugin>
</plugins>
</build>

 

Heroku ‘da uygulamayı çalıştırmak için komut ile tetiklemeliyiz.  .travis.yml de komutları çalıştırıyor fakat biz bu dosya çalıştıktan sonra komut vermek isityoruz. Heroku tarafından sağlanan bu dosya Procfile  olarak adlandırılıyor.

travis.yml ile aynı dizinde şu isim ile bir dosya eklenmelidir.

Procfile

web: java $JAVA_OPTS -jar baseapp/target/dependency/jetty-runner.jar --port $PORT baseapp/target/*.war

 

Projemizde eklediğimiz her dosya, yazdığımız her kod Travis-CI tarafından izlendiğinden otomatik olarak yeni eklediğimiz dosyayı çalıştırdıktan sonra uygulamamız çalışıyor. Hemen kontrol edelim.

Heroku üzerindeki projemizin settings bölümünden bu linke ulaşabilirsiniz.

https://jsf-travis-ci-heroku.herokuapp.com

 

Heroku ile projeyi yayınlamak için, Heroku projenin ana klasörünün altında pom.xml var mı diye kontrol ediyor.  Bu durumda şöyle bir hata alabilirsiniz.

App not compatible , Could not find pom.xml

Bu durumda  yukarıda anlattığım git checkout tags/v0.0.2 bölümü bu problemi ortadan kaldırmış oluyor

Projemizi yayınladık. Biraz projemize renk katalım.
Projemizde geliştirmek istediğimiz yeni özellikleri bir iş akışı oluşturarak continous delivery yapmaya çalışacağız.  🙂

Aslında projemizdeki geliştirmeleri belirli kurallar yardımıyla canlı ortamda kullanıcılar ile buluşturacağız.

Heroku üzerindeki projemizden Deploy bölümünden Choose a pipeline/Create new pipeline  butonu yardımı ile akışımıza başlayalım.

pipeline-jsf-travis-ci-heroku

 

Pipeline içeriğine biraz göz atalım.

Burada 3 ana bölüm var.

Review Apps bölümü

Github üzerinden her pull request yapıldığında,geliştirmeyi yapan kişiye
gönderdiği kod ile birlikte uygulamanın son durumunun ne olacağını göstermek için
bir link verilmesine yardımcı olur.

Staging bölümü

Her an canlıya çıkılabilecek durumda olan kodumuzun son halidir. Buradan bir buton yardımı ile canlı ortama kodumuzu taşıyabiliyoruz. Continuous delivery olayının yapıldığını vurgulayan kısımdır. Tabii ki bu çok küçük bir kısımdır.

Production bölümü

Projemizin canlı ortamdaki halidir.

Development bölümü

Isteğe bağlı olarak açılabiliyor. Bu bölüm için gitflow workflow ile projemizi geliştirirken işimize yarıyor. Biz bu projede kullanmayacağız.

Hemen ayarlarımızı yapmaya başlayalım.

pipeline-jsf-travis-ci-heroku2

 

Enable Review Apps  >>   Create an app.json  >>   Sayfanın en altından Commit to Repo >>    Create new review apps for new pull requests automatically   >>  Enable seçiyoruz.

 

Artık uygulamamız github üzerinden pull-request gönderilmeye hazır.

Örneklemeye başlayalım.

Projemiz açıldığında başlık kısmı kırmızı yazılması istenilen bir geliştirme yapılmak isteniyor hemen geliştirmemizi yapıp gönderelim.

Github üzerinden patch-1 isimli bir branch oluşturup pull request gönderiyoruz.

 

https://github.com/keramiozsoy/jsf-travis-ci-heroku/tree/patch-1

https://github.com/keramiozsoy/jsf-travis-ci-heroku/pull/1

 

Pull request gönderildiği için Travis-CI hemen  .travis.yml dosyasındaki komutları çalıştırmaya başladı.

pipeline-jsf-travis-ci-heroku3

 

Heroku da Review Apps bölümünde yapılan değişiklikler sayesinde bize gönderilen geliştirmenin nasıl olduğuna bakabileceğimiz bir ortam, sunucu ayağa kaldırdı.

pipeline-jsf-travis-ci-heroku4

Gönderilen geliştirmeye Open app in browser linki üzerinden ulaşabiliriz.Biz proje yayınlayan olarak Heroku üzerinde buradan görebilirken , Github üzerinde gönderilen geliştirmenin yanında View Deployment butonu ile geliştiren kişi de görebiliyor.


https://jsf-travis-ci-heroku-pr-1.herokuapp.com/

pipeline-jsf-travis-ci-heroku5
Heroku üzerindeki Staging bölümünde hiç bir değişiklik olmadığını görebilirsiniz.


https://jsf-travis-ci-heroku.herokuapp.com/

Yapılan geliştirmeyi Staging bölümünde görmek istersek github üzerinden pull request


https://github.com/keramiozsoy/jsf-travis-ci-heroku/pull/1

merge yapılmalıdır.

Staging bölümünden uygulamamızda değişikliği görebiliyoruz.

Buraya kadar geliştirmelerimizi yaptık . Bir çok kişinin projemize katkı yaptığı zaman yeni geliştirmeleri görebilmemizi sağlayan ortamı hazırladık ve hatta bunu uygulamamıza dahil ettik ve gördük.

Peki geliştirmeleri uygulamamıza dahil etmek istiyoruz fakat halihazırda uygulamamızı kullananlar mevcut. Her yeni geliştirmeyi belirli periyotlar ile canlı ortama kullanıcılarımıza sunmak istiyoruz. Hatta birden fazla canlı ortamda aynı uygulamayı koşturan sunucumuz mevcut.

Nasıl yapalım ? Ne edelim ?

Production bölümünden yeni bir uygulama oluşturuyoruz

Staging bölümündeki  Promote to Production/Promote butonu yardımıyla canlı ortama tüm geliştirmeleri alıyoruz.

pipeline-jsf-travis-ci-heroku6

Canlı ortamdaki değişiklikleri şuradan görebiliriz.

https://jsf-travis-ci-heroku-prod.herokuapp.com/

Burası aslında tamamen ayrı bir uygulama fakat aynı pipeline içerisinde olduğundan iletişim kurulabiliyor ve uygulamamızı sağlıklı şekilde paylaşabiliyoruz.

Github Link :
https://github.com/keramiozsoy/jsf-travis-ci-heroku

Teşekkürler, İyi Çalışmalar 🙂

Tagged with: , , , , , , , , , , , , ,
Devops, GIT, JAVA SERVER FACES kategorisinde yayınlandı

Continuous Integration, Continuous Delivery, Continuous Deployment Nedir?

Continuous Integration ?

Uygulamızın hızlıca sürümlenebilmesine odaklanan araçlardır.

Merkezi bir kod deposuna gönderilen her yeni kod, kontrol veya test edilmesi için bu uygulamalar yardımıyla belirlenen kurallara göre çalıştırılır.

Bu uygulamalar yardımıyla elimizde test edilmiş  bir kodumuz olur.

Örnek Araçlar
Jenkins, Travis-CI, Circle-CI, Bamboo

 

ci-cd-cd

 

Continuous Delivery ?

Continuous integration daha genişletilmiş halidir.

test edilmiş kodumuzu
örneğin canlı ile aynı özelliklere sahip olan
bir ortama deploy yaparak farklı
test senaryolarını deneriz.
Tüm bu adımların ardından istediğimiz bir anda
bir buton yardımıyla her durumu test edilen
kodumuzu canlı ortama almamızı sağlarız.

Bu senaryo continuous delivery olarak adlandırılır.

Örnek Araçlar
GoCD, CodeShip, Appveyor, Meister

Continuous Deployment ?

Continuous integration daha genişletilmiş halidir.
Continuous delivery senaryosunda kodumuzu
isteğimiz bir zamanda manuel
bir adım ile canlıya alırken
bu senaryoda artık herşey otomatize edilmiştir

Örnek
AWS CodeDeploy, DeployBot, Octopus Deploy

Örnek içindeki uygulamalar farklı alanlarda
faaliyet gösterebilmektedirler. Fikir oluşturması bakımından
eklenmiştir.

Yararlı Linkler
https://www.atlassian.com/continuous-delivery/ci-vs-ci-vs-cd

Teşekkürler, İyi Çalışmalar 🙂

Tagged with: , ,
Devops kategorisinde yayınlandı

Spring Boot Uygulaması Geliştirelim

Spring Boot ile rest servis isteklerine cevap verebilecek bir java uygulaması geliştireceğiz.

Uygulamamızın iskeletini ve kütüphanelerini yönetmek için Gradle kullanacağız.Şu link üzerinden inceleyebilirsiniz

keramiozsoy.wordpress.com/gradle

Terminalimizi açıp çalışma alanımıza gidelim.

/home/user/workarea/spring-boot-sample

Java dosyalarının bulunacağı klasörlerimizi oluşturalım.

mkdir -p src/main/java/hello

Uygulamamızda iki adet java sınıfı olacak.

App.java  sınıfı projemizi ayağa kaldırmamızı sağlarken,  NameController.java sınıfı istekleri karşılayacak olan url bilgisini ve metottan dönmesi gereken işlemleri yapıp dönecek.
Projede kullanılan bazı noktaları açıklayalım.

@SpringBootApplication   >>
Uygulamamızın başlangıç noktası için gereklidir.
@RestController = @Controller + @ResponseBody  >>
Controller
ile koda gelen istekleri alacağımız sınıfları işaretliyor, ResponseBody ile metodları işaretliyorduk. Artık RestController ile ortak bir yerden bunu kontrol ediyor ve bize json formatında veri dönmesini sağlıyor.

@RequestMapping   >>
Url belirliyoruz.

Sınıflara bakalım.

 App.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {

  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }
}

NameController.java

package hello;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class NameController {

private static final String template = "Hello, %s!";
 private final AtomicLong counter = new AtomicLong();

@RequestMapping("/")
 public String home(){
 return "home :)";
 }

@RequestMapping("/sendName")
 public String sendName(@RequestParam(value="nameParam", defaultValue="Noo!!") String name) {
 return counter.incrementAndGet() + " - " + String.format(template, name);
 }
}

Projemizi gradle ile çalıştırabilmek için build.gradle dosyasını oluşturmalıyız.
Oluşturduktan sonra projemizin ağaç yapısı aşağıdaki şekildedir.

 spring-boot-sample
 ├── build.gradle
 └── src
     └── main
         └── java
             └── hello
                ├── App.java
                └── NameController.java

Peki build.gradle dosyasına içerisinde spring boot uygulaması geliştirebilmek için eklemiz gerekenlere bakalım.

Gradle ile pluginleri yönetmek için plugin lerin bulunduğu site üzerinden springframework yazarak bağımlılıkları buluyoruz.

https://plugins.gradle.org

pluginimizin ismi aşağıdadır.

org.springframework.boot

Bağımlılıkları ekleyelim.

build.gradle

buildscript {
 repositories {
   mavenCentral()
 }
 dependencies {
   classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.2.RELEASE")
 }
}

apply plugin: 'org.springframework.boot'

Öncekilere ek olarak uygulamamız java uygulaması olduğu için gerekli plugin ekliyoruz.

apply plugin : 'java'

Uygulamamıza rest uygulaması olarak çalışabilmesi için gerekli plugin ekliyoruz.

apply plugin: 'io.spring.dependency-management'

repositories {
 mavenCentral()
}

dependencies {
 compile("org.springframework.boot:spring-boot-starter-web")
}

Peki spring-boot-starter-web isimli bağımlılık nedir ? Ne işe yarar?

Spring framework bir çok alt module sahip bir çatıdır. Bu modullerden biri spring-boot-starter-web dir. Bu modul projemizi tek başına sunucu kurulumu yapılmadan kullanabilmeyi ve isteklere cevap vermeyi sağlar. Uygulamamıza eklemek istediğimiz özelikleri tek tek bu şekilde ekleyebilirsiniz. Peki bunlar nereden öğrenebiliriz

Spring boot github hesabından bakabiliriz.

https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-starters

Bu adımları yaptıktan sonra uygulamamız derlendikten sonra jar dosyası üretilecek ama biz bu ismi özelleştirmek istiyorsak şu eklemeyi yapabiliriz.Fakat zorunlu değildir.

bootJar {
 baseName = 'app'
 version = '0.0.1'
}

Hadi projemizi derleyip çalıştıralım.

build.gradle dosyasının bulunduğu dizin içerisinde şu komutları çalıştırabiliriz.

gradle bootrun

veya

gradle build 
java -jar build/libs/app-0.0.1.jar

Komut Çıktısı:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.2.RELEASE)

2018-05-11 07:50:10.440  INFO 7542 --- [           main] hello.App                                : Starting App on host with PID 7542 (/home/user/workarea/spring-boot-sample/build/libs/app-0.0.1.jar started by root in /home/user/workarea/spring-boot-sample)
2018-05-11 07:50:10.448  INFO 7542 --- [           main] hello.App                                : No active profile set, falling back to default profiles: default
2018-05-11 07:50:10.598  INFO 7542 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@1e1023e: startup date [Fri May 11 07:50:10 EDT 2018]; root of context hierarchy
2018-05-11 07:50:12.299  INFO 7542 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2018-05-11 07:50:12.355  INFO 7542 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-05-11 07:50:12.355  INFO 7542 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.31
2018-05-11 07:50:12.384  INFO 7542 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/i386:/lib:/usr/lib]
2018-05-11 07:50:12.513  INFO 7542 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-05-11 07:50:12.513  INFO 7542 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1923 ms
2018-05-11 07:50:12.738  INFO 7542 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2018-05-11 07:50:12.741  INFO 7542 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-05-11 07:50:12.741  INFO 7542 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-05-11 07:50:12.741  INFO 7542 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-05-11 07:50:12.741  INFO 7542 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-05-11 07:50:12.979  INFO 7542 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-05-11 07:50:13.310  INFO 7542 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@1e1023e: startup date [Fri May 11 07:50:10 EDT 2018]; root of context hierarchy
2018-05-11 07:50:13.439  INFO 7542 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/sendName]}" onto public java.lang.String hello.NameController.sendName(java.lang.String)
2018-05-11 07:50:13.444  INFO 7542 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String hello.NameController.home()
2018-05-11 07:50:13.453  INFO 7542 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-05-11 07:50:13.453  INFO 7542 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-05-11 07:50:13.514  INFO 7542 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-05-11 07:50:13.515  INFO 7542 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-05-11 07:50:13.745  INFO 7542 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-05-11 07:50:13.819  INFO 7542 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-05-11 07:50:13.821  INFO 7542 --- [           main] hello.App                                : Started App in 4.114 seconds (JVM running for 4.644)

 

Bu komutlar bize hazır  Tomcat sunucusu ayağa kaldırıp 8080 portundan istekleri beklemesini sağladı.

Tarayıcımız açalım ve istek gönderelim.

http://localhost:8080/

Çıktı :

home 🙂

http://localhost:8080/sendName?nameParam=kerami

1 – Hello, kerami!

Artık isteklerimize cevap veren bir uygulamaya sahip olduk.

Github Link

https://github.com/keramiozsoy/spring-boot-samples/tree/master/spring-boot-sample

Teşekkürler, İyi Çalışmalar 🙂

 

Springframework kategorisinde yayınlandı

Gradle İle Java Projesi Derlemek, Kütüphane Eklemek ve Çalıştırmak

gradle

 

Gradle yardımıyla bir java projesini oluşturmak istiyoruz.Terminali açıyoruz

/home/user/workarea/gradle

Çalışma alanımıza gidiyoruz.

mkdir gradleSample
cd gradleSample
mkdir -p src/main/java/hello 

Dosyamızı oluşturup kodumuzu yazalım.

vi App.java
package hello;
public class App {
 public static void main(String[] args) {
 System.out.println("Hello App !!!");
 }
}

 

Projemizi derleyebilmek için build.gradle isimli bir dosya oluşturmalıyız.Ve içerisine java dosyalarımız derlemek istediğimizi belirtmeliyiz

vi build.gradle

apply plugin: 'java'

Kaydedip kapattıktan sonra projemizin ağaç yapısı şu şekildedir.

gradleSample
 ├── build.gradle
 └── src
    └── main
       └── java
          └── hello
             └── App.java

 

Projemizi derleme aşamasına geçelim.

build.gradle dosyasını içeren dizin içerisinde şu komutu çalıştıralım

gradle build

Projemizde yeni dizin ve dosyalar oluştu.

 gradleSample
 ├── build
 │   ├── classes
 │   │   └── java
 │   │       └── main
 │   │           └── hello
 │   │               └── App.class
 │   ├── distributions
 │   │   ├── gradleSample.tar
 │   │   └── gradleSample.zip
 │   ├── libs
 │   │   └── gradleSample.jar
 │   ├── scripts
 │   │   ├── gradleSample
 │   │   └── gradleSample.bat
 │   └── tmp
 │   ├── compileJava
 │   └── jar
 │   └── MANIFEST.MF
 ├── build.gradle
 └── src
     └── main
         └── java
             └── hello
                 └── App.java

 

App.class  dosyası  tek başına çalıştırılabilir. Fakat biz projemizi tek bir yerden çalıştırmak istiyoruz.
gradleSample.jar isimli dosyayı çalıştırmak için gerekli eklemeleri yapalım.

vi build.gradle

Dosyamızın içine ekleyelim.

apply plugin: 'application'
mainClassName = 'hello.App'

Kaydetikten sonra uygulamamızı tekrar derleyelim.

gradle build

 

Derlenmiş gradle dosyalarını temizlemek için bu komutu kullabililiriz fakat bu adımda zorunlu değildir.

gradle clean

 

Uygulamamızı çalıştıralım.

gradle run

Komut Çıktısı:

> Task :run
Hello App !!!
BUILD SUCCESSFUL in 0s2 actionable tasks: 1 executed, 1 up-to-date

Projemiz çalıştı 🙂

Projemizin çalıştırılabilir dosyasının adı değiştirilebiliriz.

vi build.gradle

dosyamıza ekleyelim.

jar {
 baseName = 'testApp'
 version = '0.0.1'
}

 

Projemizi derleyip görelim.

gradle build

 

gradleSample
 ├── build
 │   ├── classes
 │   │   └── java
 │   │   └── main
 │   │   └── hello
 │   │   └── App.class
 │   ├── distributions
 │   │   ├── gradleSample.tar
 │   │   └── gradleSample.zip
 │   ├── libs
 │   │   └── testApp-0.0.1.jar
 │   ├── scripts
 │   │   ├── gradleSample
 │   │   └── gradleSample.bat
 │   └── tmp
 │   ├── compileJava
 │   └── jar
 │   └── MANIFEST.MF
 ├── build.gradle
 └── src
 └── main
 └── java
 └── hello
 ├── App.class
 └── App.java

 

testApp-0.0.1.jar isimli dosya oluştu 🙂

Projemize yeni bir kütüphane nasıl ekleniyor inceleyelim.

Örneğin saat bilgisi görüntülenmek istiyor. Projemize koyu yazılan yerleri ekledik.

package hello;
import org.joda.time.LocalTime;

public class App {
 public static void main(String[] args) {
 System.out.println("Hello App !!!");
 
 LocalTime currentTime = new LocalTime();
 System.out.println("The current local time is: " + currentTime);

}
}

 

gradle run

ile çalıştırmaya çalıştırdığımızda hata alacağız. Çünkü bu bir kütüphane ve bir yerden projemize dahil edilip ilişkilendirilmesi lazım.

vi build.gradle

Dosyamıza aşağıdaki satırları ekliyoruz.

repositories {
 mavenCentral()  // Hangi depodan kütüphaneleri çekeceği
}

dependencies { // iki gösterimde aynı kütüphaneyi çekebiliyor
 //compile "joda-time:joda-time:2.9.9" 
 compile group: 'joda-time', name: 'joda-time', version: '2.9.9'
}

 

Projemiz derleyip çalıştıralım.

gradle build run

Komut çıktısı:

> Task :run
Hello App !!!
The current local time is: 14:48:47.663

projemiz çalıştı 🙂

 

Gradle biz şöyle bir kolaylık sağlıyor. Projemizi gradle yüklü olan bir ortamda
derledikten sonra gradle yüklü olmayan bir ortamda linux,unix veya windows
farketmeksizin çalıştırılabilecek hale getiriyoruz.

Gradle yüklü olan ortamda build.gradle dosyasının bulunduğu dizinde istediğimiz sürüm ile derliyoruz.

gradle wrapper --gradle-version 2.13

Artık projemizi  farklı bir ortamda çalıştırabiliriz.

./gradle build run
veya
gradle.bat build run ( bunu denemedim :) )

 

Github Link :
https://github.com/keramiozsoy/gradleSamples/tree/master/gradleSample

Teşekkürler, İyi Çalışmalar 🙂

 

Tagged with: , , , , , , ,
GRADLE kategorisinde yayınlandı

Ubuntu Gradle Yükleyelim

gradle
Merhabalar,

Gradle projelerimizin bağımlılıkları yönetmek için kullanılan bir araçtır.

Kendine özgü komut kümesi ile projelerimiz derlenebilir ve hatta çalıştırılabilir.

Kurulumu yapacağımız klasöre gidelim.

/home/user/gradle

Terminalimizi açalım.

Gradle kendi sitesi üzerinden istediğimiz
sürümü indirelim.

wget https://services.gradle.org/distributions/gradle-4.7-all.zip

Sıkıştırılmış dosyayı bulunduğumuz dizine çıkaralım

unzip gradle-4.7-all.zip

Komut satırı üzerinden kullabilmek için  .bashrc dosyasına gerekli eklemeleri yapalım.
Oturum açtığımız kullanıcının ana dizinine gidelim.

vi /home/user/.bashrc

Aşağıdaki tanımlamaları ekleyelim

GRADLE_HOME=/home/user/gradle/gradle-4.7/bin
export PATH=$PATH:$GRADLE_HOME

Kontrol etmek için terminali açıp kapatmak yerine
şu komutu çalıştıralım.

source /home/user/.bashrc

Kontrol edelim.

gradle -v

komut çıktısı

Welcome to Gradle 4.7!

Here are the highlights of this release:
 - Incremental annotation processing
 - JDK 10 support
 - Grouped non-interactive console logs
 - Failed tests are re-run first for quicker feedback

For more details see https://docs.gradle.org/4.7/release-notes.html


------------------------------------------------------------
Gradle 4.7
------------------------------------------------------------

Build time: 2018-04-18 09:09:12 UTC
Revision: b9a962bf70638332300e7f810689cb2febbd4a6c

Groovy: 2.4.12
Ant: Apache Ant(TM) version 1.9.9 compiled on February 2 2017
JVM: 1.7.0_80 (Oracle Corporation 24.80-b11)
OS: Linux 4.2.0-27-generic amd64

Teşekkürler, Iyi Çalışmalar 🙂

 

GRADLE kategorisinde yayınlandı

Operatörler Özet – Summary of Operators

java

Atama Operatoru
=

Aritmetik Operatorler
+ Ekleme (String ifadeler birlestirmek icin kullanilabilir)
– Silme
* Çarpma
/ Bölme
% Kalan Bulma

Tekli Operatorler
+ Değerin pozitif olduğunu gösterir

– Degerin negatif olduğunu gösterir

++ Degiskenin değerini bir arttırır.

— Degiskenin değerini bir eksiltir.

! Mantıksal olarak boolean ifadelerin tersini alır

 

Eşitlik ve Ilişkisel Operatorler
== Eşitttir
!= Eşit değildir
> Büyüktür
>= Büyük veya eşittir
< Küçüktür
<= Küçük veya eşittir

Koşullu ifadeler
&& Ve
|| Veya
?: Üçlü karşılaştırma (if-then-else ifadesinin tek satırda kullanımı)

Tip Karşılaştırma Operatörü
instanceof Karşılaştırmak istediğim objenin tipinin istediğim obje tipi olup olmadığını anlayabiliriz.

Bit Düzeyin ve Bit Kaydırma Işlemleri
~ Tek tek tüm bitlerin mantıksal karşılığını döndürür.
<< Sayı değeri büyür. Sağdan basamak eklemek.
>> Sayı değeri küçülür. Soldan basamak eklemek.
>>> Basamak olarak sayıları sağa kaydır.Basamak sayısı değişmez (Yönsüz)
<<< Basamak olarak sayıları solak kaydır. Basamak sayısı değişmez (Yönsüz)
& Bit bazında ve (Basamak basamak karşılaştırmak)
^ Bit bazında veya tersi (xor) (Basamak basamak karşılaştırmak)
| Bit bazında veya (Basamak basamak karşılaştırmak)

 

Teşekkürler, İyi çalışmalar 🙂

 

JAVA kategorisinde yayınlandı