{"id":2032,"date":"2018-04-11T16:58:19","date_gmt":"2018-04-11T14:58:19","guid":{"rendered":"http:\/\/miroslaw.borodziuk.eu\/?p=2032"},"modified":"2018-05-18T09:33:41","modified_gmt":"2018-05-18T07:33:41","slug":"a","status":"publish","type":"post","link":"http:\/\/miro.borodziuk.eu\/index.php\/2018\/04\/11\/a\/","title":{"rendered":"CI\/CD projekt\u00f3w PHP na Jenkinsie \u2013 Automatyzacja"},"content":{"rendered":"<p>Mimo, \u017ce PHP jest j\u0119zykiem interpretowanym a kod PHP nie wymaga kompilacji, to developerzy przeprowadzaj\u0105 np. generacj\u0119 lub transformacj\u0119 kodu autoloadera. Doskona\u0142ym narz\u0119dziem s\u0142u\u017c\u0105cym do zautomatyzowania procesu budowy oprogramowania jest<a href=\"http:\/\/ant.apache.org\/\"> <em>Apache Ant<\/em><\/a>. To co r\u00f3\u017cni <em>Ant<\/em> i np.\u00a0 znany z Linuksa <em>Make<\/em> jest to, \u017ce <em>Ant<\/em> u\u017cywa plik\u00f3w w formacie <a title=\"XML\" href=\"https:\/\/pl.wikipedia.org\/wiki\/XML\">XML<\/a> do opisu procesu budowy i jego zale\u017cno\u015bci, podczas gdy <em>Make<\/em> ma w\u0142asny format <em>Makefile<\/em>. Projekt <em>Ant<\/em> jest w zwi\u0105zku z tym przeno\u015bny, <em>Make<\/em> nie. Domy\u015blnie plik XML\u00a0 w <em>Ant<\/em> nazywa si\u0119<code> build.xml.<\/code><\/p>\n<p><!--more--><\/p>\n<p>Rozwa\u017cmy nast\u0119puj\u0105cy projekt umieszczony w katalogu <code>\/root<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">.\r\n\u251c\u2500\u2500 build\r\n\u2502   \u251c\u2500\u2500 phpcs.xml\r\n\u2502   \u251c\u2500\u2500 phpmd.xml\r\n\u2502   \u251c\u2500\u2500 src_autoload.php.in\r\n\u2502   \u2514\u2500\u2500 tests_autoload.php.in\r\n\u251c\u2500\u2500 build.xml\r\n\u251c\u2500\u2500 phpunit.xml.dist\r\n\u251c\u2500\u2500 src\r\n\u2502   \u2514\u2500\u2500 autoload.php\r\n\u2514\u2500\u2500 tests\r\n\u2514\u2500\u2500 autoload.php<\/pre>\n<p>Katalog build zawiera pliki konfiguracyjne XML dla PHP_CodeSniffer (phpcs.xml), PHPMD (phpmd.xml). PHP_CodeSniffer i PHPMD to narz\u0119dzia do statycznej analizy kodu PHP, kt\u00f3rym przyjrzymy si\u0119 bli\u017cej w kolejnym artykule o Jenkinsie i PHP, dotycz\u0105cym tzw. Continous Inspection (ci\u0105g\u0142ej inspekcji). Plik phpunit.xml (lub phpunit.xml.dist) to plik konfiguracyjny projektu PHPUnit. Pliki src\/autoload.php, tests\/autoload.php zawieraj\u0105 kod autoloadera dla aplikacji i zestaw test\u00f3w.<\/p>\n<p>Plik <em>Ant<\/em> bulid.xml definiuje tzw. targety czyli cele (zestawy zada\u0144), kt\u00f3re maj\u0105 zosta\u0107 wykonane. Podczas uruchamiania <em>Ant<\/em> istnieje mo\u017cliwo\u015b\u0107 wybrania, kt\u00f3re targety maj\u0105 zosta\u0107 uruchomione. Je\u017celi nie jest podany \u017caden target to wykonywany jest domy\u015blny projekt. Ka\u017cdy target mo\u017ce zale\u017ce\u0107 od innego targetu, <em>Ant<\/em> rozpoznaje zale\u017cno\u015bci. Zadanie to kod (np. skrypt), kt\u00f3ry ma by\u0107 wykonany.<\/p>\n<p>&nbsp;<\/p>\n<p>Poni\u017cszy tekst pochodzi z tej <a href=\"https:\/\/4programmers.net\/Java\/Ant\">strony<\/a> i jest nieco przeze mnie zmodyfikowany. Umieszczam tutaj ten tekst gdy\u017c stanowi on bardzo dobre wprowadzenie do <em>Apache Ant<\/em>.<\/p>\n<p><span style=\"color: #3366ff;\">Wst\u0119p<\/span><\/p>\n<p><em>Apache Ant<\/em> jest narz\u0119dziem wspomagaj\u0105cym i automatyzuj\u0105cym proces kompilacji. Umo\u017cliwia definiowanie skrypt\u00f3w za pomoc\u0105 j\u0119zyka XML, kt\u00f3re to skrypty wykonuj\u0105 zadania. Cytuj\u0105c dokumentacj\u0119:<\/p>\n<blockquote><p>Apache Ant is a Java-based build tool. In theory, it is kind of like make, without make&#8217;s wrinkles.<\/p><\/blockquote>\n<p>Mo\u017cna zatem za\u0142o\u017cy\u0107, \u017ce <em>Ant<\/em> powinien by\u0107 pierwszym narz\u0119dziem jakie b\u0119dzie nam s\u0142u\u017cy\u0107 w trakcie kompilowania naszych program\u00f3w.<br \/>\nStrona domowa projektu: <a href=\"http:\/\/ant.apache.org\">http:\/\/ant.apache.org<\/a><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Struktura projektu<\/span><\/p>\n<p>Ant jest narz\u0119dziem wymagaj\u0105cym stosunkowo prostej struktury projektu. Po \u015bci\u0105gni\u0119ciu go ze strony nale\u017cy skonfigurowa\u0107 zmienn\u0105 <code>ANT_HOME<\/code> tak by wskazywa\u0142a na katalog w kt\u00f3rym zainstalowano <em>anta<\/em>, oraz do zmiennej <code>PATH<\/code> doda\u0107 \u015bcie\u017ck\u0119 <code>$ANT_HOME\/bin<\/code> (w windowsie: %ANT_HOME%\/bin). Nast\u0119pnie sprawdzamy czy wszystko jest prawid\u0142owo skonfigurowane:<\/p>\n<pre class=\"lang:sh decode:true\">$ ant\r\nBuildfile: build.xml does not exist!\r\nBuild failed<\/pre>\n<p>Jak wida\u0107 by utworzy\u0107 projekt wystarczy w katalogu umie\u015bci\u0107 plik <code>build.xml<\/code>. Jest to plik XML w kt\u00f3rym definiujemy w\u0142a\u015bciwo\u015bci projektu. Najprostsza jego wersja wygl\u0105da tak:<\/p>\n<pre class=\"lang:sh decode:true \">&lt;?xml version=\"1.0\" encoding=\"iso-8859-2\"?&gt;\r\n&lt;project name=\"Project name\" basedir=\".\" default=\"clean\"&gt;\r\n&lt;!-- --&gt;\r\n&lt;\/project&gt;<\/pre>\n<p>Gdzie:<\/p>\n<p><code>name<\/code> &#8211; nazwa projektu, kt\u00f3ra nie jest obowi\u0105zkowa.<br \/>\n<code>basedir<\/code> &#8211; \u015bcie\u017cka bazowa od kt\u00f3rej s\u0105 liczone wszystkie \u015bcie\u017cki wzgl\u0119dne. Te\u017c nieobowi\u0105zkowe, ale domy\u015blnie jest to \u015bcie\u017cka do folderu z plikiem <code>build.xml<\/code>.<br \/>\n<code>default<\/code> &#8211; domy\u015blne zadanie, kt\u00f3re b\u0119dzie wykonane je\u017celi nie podamy zada\u0144 do wykonania. Od wersji 1.6 biblioteki, ka\u017cdy projekt posiada domy\u015blnie skonfigurowane wszystkie zadania dostarczone razem z bibliotek\u0105.<\/p>\n<p>Jak zatem \u0142atwo zauwa\u017cy\u0107, <em>ant<\/em> pozwala na bardzo swobodn\u0105 konfiguracj\u0119 projektu. Niestety w starszych wersjach biblioteki brak konfiguracji domy\u015blniej wymusza\u0142 tworzenie du\u017cej ilo\u015bci &#8220;domy\u015blnego&#8221; kodu. Obecnie nie jest to konieczne, ale cz\u0119sto trzeba si\u0119 napisa\u0107 by odpowiednio skonfigurowa\u0107 projekt. Do prawid\u0142owego dzia\u0142ania wystarczy JDK w wersji 1.2, ale producenci rekomenduj\u0105 u\u017cycie JDK w wersji 1.5.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Cele i zadania<\/span><\/p>\n<p>Projekt w <em>Ant<\/em> jest podzielony na cele (target), kt\u00f3re zawieraj\u0105 zadania (task). Cele definiujemy sami, a zadania s\u0105 dostarczone wraz z bibliotek\u0105, ale mo\u017cna i samemu stworzy\u0107 zadanie poprzez rozszerzenie klasy Task.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Target &#8211; cel<\/span><\/p>\n<p>Cel jest logicznym krokiem w procesie kompilacji. Sk\u0142ada si\u0119 z zada\u0144 i opisuje jaki\u015b etap projektu. Przyk\u0142adem celu mo\u017ce by\u0107 kompilacja, umieszczenie na serwerze, wykonanie test\u00f3w czy te\u017c synchronizacja z SVN. W naszym projekcie przygotujemy wszystko od podstaw wykorzystuj\u0105c cele i zadania. Stw\u00f3rzmy wi\u0119c katalog z plikiem <code>build.xml<\/code> i dodajmy pierwsze zadanie:<\/p>\n<pre class=\"lang:sh decode:true\">&lt;?xml version=\"1.0\" encoding=\"iso-8859-2\"?&gt;\r\n&lt;project name=\"Project name\" basedir=\".\" default=\"create\"&gt;\r\n&lt;description&gt;Tutorial ANT na http;\/\/4programmers.net\/java\/Ant&lt;\/description&gt;\r\n\r\n&lt;!-- =================================\r\ntarget: create\r\n================================= --&gt;\r\n&lt;target name=\"create\" depends=\"\" description=\"Tworzy struktur\u0119 projektu\"&gt;\r\n\r\n&lt;\/target&gt;\r\n&lt;\/project&gt;<\/pre>\n<p>Cel posiada obowi\u0105zkow\u0105 nazw\u0119 i opcjonalny opis. Mo\u017ce te\u017c zale\u017ce\u0107 od innych cel\u00f3w np. tworzenie archiwum jar zazwyczaj musi by\u0107 wykonane po skompilowaniu kodu. Zale\u017cno\u015bci definiujemy za pomoc\u0105 atrybutu <code>depends<\/code> w kt\u00f3rym poddajemy nazwy zale\u017cnych celi rozdzielone przecinkiem.<br \/>\nDodajmy do naszego celu kilka zada\u0144, kt\u00f3re b\u0119d\u0105 nam tworzy\u0107 struktur\u0119 projektu.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Task &#8211; zadanie<\/span><\/p>\n<p>Zadanie jest pojedyncz\u0105 operacj\u0105 wykonywan\u0105 by osi\u0105gn\u0105\u0107 cel. Mo\u017ce by\u0107 to na przyk\u0142ad stworzenie katalogu, wywo\u0142anie kompilatora lub wypisanie czego\u015b w konsoli. Ilo\u015b\u0107 zada\u0144 w <em>ancie<\/em> jest ogromna. Biblioteka posiada oko\u0142o 70 wbudowanych zada\u0144, a istnieje jeszcze mo\u017cliwo\u015b\u0107 \u015bci\u0105gni\u0119cia dodatkowy bibliotek jak i stworzenia w\u0142asnego rozwi\u0105zania.<br \/>\nKa\u017cde zadanie posiada unikaln\u0105 list\u0119 parametr\u00f3w, kt\u00f3re s\u0105 przekazywane jako atrybuty lub tagi XML. Spos\u00f3b konfiguracji jest wi\u0119c do\u015b\u0107 swobodny. Z jednej strony zapewnia to du\u017c\u0105 elastyczno\u015b\u0107, ale z drugiej wymaga cz\u0119stego zagl\u0105dania do dokumentacji w celu sprawdzenia jak skonfigurowa\u0107 taki czy inny cel. Poni\u017cej nasz plik <code>build.xml<\/code> wzbogacony o definicj\u0119 zada\u0144, po wykonaniu kt\u00f3rych zostanie stworzona struktura projektu:<\/p>\n<pre class=\"lang:sh decode:true\">&lt;?xml version=\"1.0\" encoding=\"iso-8859-2\"?&gt;\r\n&lt;project name=\"Project name\" basedir=\".\" default=\"create\"&gt;\r\n&lt;description&gt;Tutorial ANT na http;\/\/4programmers.net\/java\/Ant&lt;\/description&gt;\r\n\r\n&lt;!-- =================================\r\ntarget: create\r\n================================= --&gt;\r\n  &lt;target name=\"create\" depends=\"\" description=\"Tworzy struktur\u0119 projektu\"&gt;\r\n    &lt;echo&gt;Tworz\u0119 katalog ze \u017arod\u0142ami&lt;\/echo&gt;\r\n    &lt;mkdir dir=\".\/src\/pl\/koziolekweb\/programmers\/ant\"\/&gt;\r\n    &lt;echo&gt;Tworz\u0119 katalog z testami&lt;\/echo&gt;\r\n    &lt;mkdir dir=\".\/test\/pl\/koziolekweb\/programmers\/ant\"\/&gt;\r\n    &lt;echo&gt;Tworz\u0119 katalog ze skompilowanymi klasami&lt;\/echo&gt;\r\n    &lt;mkdir dir=\".\/bin\/classes\/\"\/&gt;\r\n    &lt;echo&gt;Tworz\u0119 katalog ze skompilowanymi testami&lt;\/echo&gt;\r\n    &lt;mkdir dir=\".\/bin-test\"\/&gt;\r\n  &lt;\/target&gt;\r\n&lt;\/project&gt;<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Przyk\u0142adowe zadania wbudowane<\/span><\/p>\n<p>W powy\u017cszym przyk\u0142adzie wykorzystali\u015bmy dwa zadania wbudowane. Pierwsze z nich echo pozwala na wypisanie komunikatu na ekranie. Drugie mkdir tworzy katalogi je\u017celi nie istniej\u0105. Zadania wbudowane w wi\u0119kszo\u015bci odpowiadaj\u0105 potrzebom projekt\u00f3w. Do najpopularniejszych nale\u017c\u0105 javac uruchamiaj\u0105ce kompilator, jar tworz\u0105ce archiwum i javadoc s\u0142u\u017c\u0105ce do generowania dokumentacji. Innymi przydatnymi zadaniami s\u0105 copy s\u0142u\u017c\u0105ce do kopiowania plik\u00f3w, delete usuwaj\u0105ce pliki i zip pozwalaj\u0105ce na pakowanie plik\u00f3w.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Parametryzowanie zada\u0144<\/span><\/p>\n<p>Nasze zadania zazwyczaj b\u0119d\u0105 wsp\u00f3\u0142dzieli\u0107 niekt\u00f3re informacje. S\u0105 to przede wszystkim dane o \u015bcie\u017ckach z kodem \u017ar\u00f3d\u0142owym, nazwach plik\u00f3w jar\/war\/ear, \u015bcie\u017ckach do bibliotek. Warto trzyma\u0107 je w jednym miejscu i mie\u0107 mo\u017cliwo\u015b\u0107 szybkiej ich edycji. <em>Ant<\/em> udost\u0119pnia dwie metody pozwalaj\u0105ce na osi\u0105gni\u0119cie tego celu. Pierwsz\u0105 z nich jest mo\u017cliwo\u015b\u0107 definiowania zmiennych bezpo\u015brednio w pliku <code>build.xml<\/code>, a drug\u0105 u\u017cycie pliku <code>build.properties<\/code>. W obu przypadkach odwo\u0142anie do warto\u015bci zmienne nast\u0119puje za pomoc\u0105 <code>${nazwa_zmiennej}<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Zmienne w pliku build.xml<\/span><\/p>\n<p>Zmienne mo\u017cemy definiowa\u0107 w pliku <code>build.xml<\/code> za pomoc\u0105 specjalnego elementu <code>&lt;property\/&gt;<\/code>. Na przyk\u0142adzie naszego pliku konfiguracyjnego b\u0119dzie to wygl\u0105da\u0107 nast\u0119puj\u0105co:<\/p>\n<pre class=\"lang:sh decode:true \">&lt;?xml version=\"1.0\" encoding=\"iso-8859-2\"?&gt;\r\n&lt;project name=\"Project name\" basedir=\".\" default=\"create\"&gt;\r\n&lt;description&gt;Tutorial ANT na http;\/\/4programmers.net\/java\/Ant&lt;\/description&gt;\r\n\r\n&lt;property name=\"src\" value=\".\/src\"\/&gt;\r\n&lt;property name=\"src.test\" value=\".\/test\"\/&gt;\r\n&lt;property name=\"target\" value=\".\/bin\/classes\/\"\/&gt;\r\n&lt;property name=\"target.test\" value=\".\/bin-test\"\/&gt;\r\n&lt;property name=\"main.package\" value=\"pl.koziolekweb.programmers.ant\"\/&gt;\r\n&lt;property name=\"main.package.dir\" value=\"pl\/koziolekweb\/programmers\/ant\"\/&gt;\r\n\r\n&lt;!-- =================================\r\ntarget: create\r\n================================= --&gt;\r\n&lt;target name=\"create\" description=\"Tworzy struktur\u0119 projektu\"&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog ze \u017arod\u0142ami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${src}\/${main.package.dir}\"\/&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog z testami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${src.test}\/${main.package.dir}\"\/&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog ze skompilowanymi klasami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${target}\"\/&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog ze skompilowanymi testami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${target.test}\"\/&gt;\r\n&lt;\/target&gt;\r\n&lt;\/project&gt;<\/pre>\n<p>Metoda ta jest dobra ale jedynie wtedy gdy warto\u015bci zmiennych s\u0105 takie same dla wszystkich os\u00f3b pracuj\u0105cych przy projekcie. Je\u017celi zmienna wymaga r\u00f3\u017cnych warto\u015bci w zale\u017cno\u015bci od np. \u015brodowiska lub osoby, kt\u00f3ra uruchamia proces to nie wskazane jest zmienianie jej za ka\u017cdym razem. Jest to szczeg\u00f3lnie uci\u0105\u017cliwe w przypadku pracy z systemami kontroli wersji. Z jednej strony nie nale\u017cy wysy\u0142a\u0107 do repozytorium pliku z wiadomo\u015bciami przydatnymi tylko nam, ale z drugiej strony nale\u017cy posiada\u0107 zawsze aktualny plik <code>build.xml<\/code>. W takim przypadku nale\u017cy u\u017cy\u0107 pliku <code>build.properties<\/code> zamiast bezpo\u015brednich wpis\u00f3w w <code>build.xml<\/code>.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">U\u017cycie pliku build.properties<\/span><\/p>\n<p>Plik ten jest typowym plikiem<code> .properties<\/code> ze wszystkimi jego zaletami i wadami (kodowanie US-ASCII, patrz Properties &#8211; pliki tekstowe). Przenie\u015bmy cz\u0119\u015b\u0107 naszych zmiennych do tego pliku:<\/p>\n<pre class=\"lang:sh decode:true \">target=.\/bin\/classes\/\r\ntarget.test=.\/bin-test\/<\/pre>\n<p>Jak wida\u0107 nie ma r\u00f3\u017cnicy pomi\u0119dzy tymi metodami definiowania zmiennych. Plik <code>build.properties<\/code> mo\u017ce by\u0107 ju\u017c wyj\u0119ty z pod kontroli wersji i nie ma potrzeby za\u015bmiecania repozytorium r\u00f3\u017cnymi wersjami konfiguracji. wystarczy tylko podlinkowa\u0107 nasz plik w pliku <code>build.xml<\/code> i gotowe.<\/p>\n<pre class=\"lang:sh decode:true \">&lt;?xml version=\"1.0\" encoding=\"iso-8859-2\"?&gt;\r\n&lt;project name=\"Project name\" basedir=\".\" default=\"create\"&gt;\r\n&lt;description&gt;Tutorial ANT na http;\/\/4programmers.net\/java\/Ant&lt;\/description&gt;\r\n\r\n&lt;property file=\"build.properties\" \/&gt;\r\n&lt;property name=\"src\" value=\".\/src\" \/&gt;\r\n&lt;property name=\"src.test\" value=\".\/test\" \/&gt;\r\n&lt;property name=\"main.package\" value=\"pl.koziolekweb.programmers.ant\" \/&gt;\r\n&lt;property name=\"main.package.dir\" value=\"pl\/koziolekweb\/programmers\/ant\" \/&gt;\r\n\r\n&lt;!-- =================================\r\ntarget: create\r\n================================= --&gt;\r\n&lt;target name=\"create\" depends=\"configure\" description=\"Tworzy struktur\u0119 projektu\"&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog ze \u017arod\u0142ami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${src}\/${main.package.dir}\" \/&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog z testami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${src.test}\/${main.package.dir}\" \/&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog ze skompilowanymi klasami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${target}\" \/&gt;\r\n&lt;echo&gt;Tworz\u0119 katalog ze skompilowanymi testami&lt;\/echo&gt;\r\n&lt;mkdir dir=\"${target.test}\" \/&gt;\r\n&lt;\/target&gt;\r\n&lt;\/project&gt;<\/pre>\n<p>&nbsp;<\/p>\n<p><code>Przyk\u0142ady<\/code><\/p>\n<p>Om\u00f3wi\u0119 teraz przyk\u0142adowy plik <code>build.xml<\/code>, kt\u00f3ry zawiera kompletny zestaw najpopularniejszych zada\u0144. Zadania zosta\u0142y tak przygotowane, \u017ce pokrywaj\u0105 najpopularniejsze wymagania dotycz\u0105ce sposobu dostarczenia kodu. Dla ograniczenia liczby plik\u00f3w wszystkie zmienne zosta\u0142y umieszczone w pliku <code>build.xml<\/code>.<\/p>\n<pre class=\"lang:sh decode:true \">&lt;?xml version=\"1.0\" encoding=\"iso-8859-2\"?&gt;\r\n&lt;project name=\"Project name\" basedir=\".\" default=\"all\"&gt;\r\n&lt;description&gt;Tutorial ANT na http;\/\/4programmers.net\/java\/Ant&lt;\/description&gt;\r\n\r\n&lt;property file=\"build.properties\" \/&gt;\r\n&lt;property name=\"target\" value=\".\/bin\/\" \/&gt;\r\n&lt;property name=\"target.classes\" value=\".\/bin\/classes\/\" \/&gt;\r\n&lt;property name=\"target.test\" value=\".\/bin-test\/\" \/&gt;\r\n&lt;property name=\"target.jar\" value=\".\/bin\/jar\" \/&gt;\r\n&lt;property name=\"lib\" value=\".\/lib\" \/&gt;\r\n&lt;property name=\"lib.junit\" value=\"${lib}\/junit4.jar\" \/&gt;\r\n&lt;property name=\"reports.tests\" value=\".\/bin-test\/raport\/\" \/&gt;\r\n&lt;property name=\"src\" value=\".\/src\" \/&gt;\r\n&lt;property name=\"src.test\" value=\".\/test\" \/&gt;\r\n&lt;property name=\"main.package\" value=\"pl.koziolekweb.programmers.ant\" \/&gt;\r\n&lt;property name=\"main.package.dir\" value=\"pl\/koziolekweb\/programmers\/ant\" \/&gt;\r\n\r\n&lt;target name=\"clean\" description=\"Usuwa katalogi ze skompilowanym kodem\"&gt;\r\n&lt;delete includeemptydirs=\"true\" failonerror=\"no\"&gt;\r\n&lt;fileset dir=\"${target.classes}\" includes=\"**\/*\" \/&gt;\r\n&lt;\/delete&gt;\r\n&lt;delete includeemptydirs=\"true\" failonerror=\"no\"&gt;\r\n&lt;fileset dir=\"${target}\" includes=\"**\/*\" \/&gt;\r\n&lt;\/delete&gt;\r\n&lt;delete includeemptydirs=\"true\" failonerror=\"no\"&gt;\r\n&lt;fileset dir=\"${target.test}\" includes=\"**\/*\" \/&gt;\r\n&lt;\/delete&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"create\" depends=\"clean\" description=\"Tworzy struktur\u0119 projektu\"&gt;\r\n&lt;mkdir dir=\"${src}\/${main.package.dir}\" \/&gt;\r\n&lt;mkdir dir=\"${src.test}\/${main.package.dir}\" \/&gt;\r\n&lt;mkdir dir=\"${target.classes}\" \/&gt;\r\n&lt;mkdir dir=\"${target.test}\" \/&gt;\r\n&lt;mkdir dir=\"${target.jar}\" \/&gt;\r\n&lt;mkdir dir=\"${lib}\" \/&gt;\r\n&lt;mkdir dir=\"${reports.tests}\" \/&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"compile\" depends=\"create\" description=\"kompiluje kod\"&gt;\r\n&lt;javac srcdir=\"${src}\" destdir=\"${target.classes}\" \/&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"test-compile\" description=\"kompiluje kod\" depends=\"compile\"&gt;\r\n&lt;javac srcdir=\"${src.test}\" destdir=\"${target.test}\" classpath=\"${lib.junit};${target.classes}\" \/&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"run-test\" depends=\"test-compile\" description=\"Uruchamia testy jednostkowe\"&gt;\r\n&lt;junit&gt;\r\n&lt;classpath&gt;\r\n&lt;pathelement location=\"${lib}\" \/&gt;\r\n&lt;pathelement location=\"${lib.junit}\" \/&gt;\r\n&lt;pathelement path=\"${target.classes}\" \/&gt;\r\n&lt;pathelement path=\"${target.test}\" \/&gt;\r\n&lt;\/classpath&gt;\r\n&lt;batchtest fork=\"yes\" todir=\"${reports.tests}\"&gt;\r\n&lt;fileset dir=\"${src.test}\"&gt;\r\n&lt;include name=\"**\/*Test.java\" \/&gt;\r\n&lt;\/fileset&gt;\r\n&lt;\/batchtest&gt;\r\n&lt;formatter type=\"xml\" \/&gt;\r\n&lt;\/junit&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"package\" depends=\"compile\" description=\"tworzy plik jar\"&gt;\r\n&lt;jar destfile=\"${target.jar}\/app.jar\"&gt;\r\n&lt;fileset dir=\"${target.classes}\" \/&gt;\r\n&lt;\/jar&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"test-package\" depends=\"test-compile\" description=\"tworzy plik jar z testami\"&gt;\r\n&lt;jar destfile=\"${target.jar}\/app-test.jar\"&gt;\r\n&lt;fileset dir=\"${target.test}\" \/&gt;\r\n&lt;\/jar&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"src-package\" description=\"tworzy plik jar ze \u017ar\u00f3d\u0142ami i \u017ar\u00f3d\u0142ami test\u00f3w\"&gt;\r\n&lt;jar destfile=\"${target.jar}\/app-src.jar\"&gt;\r\n&lt;fileset dir=\"${src}\" \/&gt;\r\n&lt;\/jar&gt;\r\n&lt;jar destfile=\"${target.jar}\/app-src-test.jar\"&gt;\r\n&lt;fileset dir=\"${src.test}\" \/&gt;\r\n&lt;\/jar&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"javadoc\"&gt;\r\n&lt;javadoc packagenames=\"pl.koziolekweb.programmers.ant*\" sourcepath=\"${src}\" defaultexcludes=\"yes\" destdir=\"${target}\/docs\/api\" author=\"true\" version=\"true\" use=\"true\" windowtitle=\"App API\" classpath=\"${target.jar}\/app.jar\" \/&gt;\r\n&lt;javadoc packagenames=\"pl.koziolekweb.programmers.ant*\" sourcepath=\"${src.test}\" defaultexcludes=\"yes\" destdir=\"${target}\/docs\/test-api\" author=\"true\" version=\"true\" use=\"true\" windowtitle=\"App tests API\" classpath=\"${lib.junit};${target.test}\"\/&gt;\r\n&lt;zip destfile=\"${target}\/docs\/api.zip\" basedir=\"${target}\/docs\/api\/\" \/&gt;\r\n&lt;zip destfile=\"${target}\/docs\/test-api.zip\" basedir=\"${target}\/docs\/test-api\/\" \/&gt;\r\n&lt;\/target&gt;\r\n\r\n&lt;target name=\"all\" depends=\"package,test-package,src-package\"&gt;&lt;\/target&gt;\r\n&lt;\/project&gt;\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Usuwanie starych plik\u00f3w<\/span><\/p>\n<p>Pierwszym celem jest <em>clean<\/em>. Usuwa on wszystkie stare skompilowane pliki, pliki <em>jar<\/em> i stare testy. Zadanie <em>delete<\/em> przyjmuje w tym przypadku list\u0119 plik\u00f3w do usuni\u0119cia z podanego katalogu, ale bez tego katalogu. W trakcie okre\u015blania zbioru plik\u00f3w, <code>fileset<\/code>, istnieje mo\u017cliwo\u015b\u0107 stworzenia listy wy\u0142\u0105cze\u0144 przez zdefiniowanie atrybuty albo elementu <code>excludes<\/code><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Tworzenie katalog\u00f3w<\/span><\/p>\n<p>Ten cel zosta\u0142 ju\u017c om\u00f3wiony wcze\u015bniej.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Kompilacja \u017ar\u00f3de\u0142 i test\u00f3w<\/span><\/p>\n<p>Te dwa cele reprezentowane przez compile i test-compile s\u0105 najwa\u017cniejszymi elementami projektu. Okre\u015blaj\u0105, kt\u00f3re katalogi zawieraj\u0105 pliki \u017ar\u00f3d\u0142owe i pozwalaj\u0105 na ich kompilacj\u0119. W przypadku compile proces jest bardzo prosty za pomoc\u0105 atrybutu srcdir okre\u015blono katalog \u017ar\u00f3d\u0142owy, a za pomoc\u0105 destdir docelowy. Kompilacja test\u00f3w jest troch\u0119 bardziej skomplikowana poniewa\u017c wymaga okre\u015blenia poza katalogiem \u017ar\u00f3d\u0142owym i docelowym te\u017c \u015bcie\u017cki z zale\u017cno\u015bciami. Mo\u017cna wykona\u0107 to zadanie na kilka sposob\u00f3w. Najprostszym jest u\u017cycie atrybutu classpath i r\u0119czne dodanie wszystkich potrzebnych element\u00f3w. Cel test-compile jest uzale\u017cnione od compile poniewa\u017c do uruchomienia test\u00f3w potrzebne s\u0105 skompilowane klasy aplikacji.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Uruchomienie test\u00f3w<\/span><\/p>\n<p>Ten cel jest troch\u0119 bardziej skomplikowany. Po pierwsze classpath jest okre\u015blony za pomoc\u0105 listy element\u00f3w pathelement. Pozwala to na budowanie d\u0142ugich \u015bcie\u017cek i na d\u0142u\u017csz\u0105, nomen omen, met\u0119 jest znacznie bardziej wygodne. Po drugie u\u017cyty zosta\u0142 element batchtest zamiast test. Pozwala on na konfiguracj\u0119 test\u00f3w na podstawie \u015bcie\u017cki, a test przyjmuje jako atrybut class pojedyncze klasy testowe.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Tworzenie pakiet\u00f3w<\/span><\/p>\n<p>Cele package,test-package i src-package maj\u0105 za zadanie utworzenie plik\u00f3w jar zawieraj\u0105cych odpowiednio aplikacj\u0119, testy, kod \u017ar\u00f3d\u0142owy aplikacji i kod \u017ar\u00f3d\u0142owy test\u00f3w.<br \/>\nTworzenie dokumentacji<\/p>\n<p>Cele javadoc tworzy dokumentacj\u0119 kodu \u017ar\u00f3d\u0142owego i test\u00f3w. Nast\u0119pnie pakuje j\u0105 do plik\u00f3w zip. Przy tworzeniu dokumentacji te\u017c nale\u017cy zdefiniowa\u0107 classpath w przeciwnym wypadku javadoc zwroci b\u0142\u0119dy podobne do tych jakie zwraca kompilator gdy nie odnajdzie zalezno\u015bci.<br \/>\nWszystko naraz<\/p>\n<p>Ostatni cel jest domy\u015blny. Uruchamia wszystkie poprzednie dbaj\u0105 o to by zale\u017cno\u015bci by\u0142y uruchamiane tylko raz.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mimo, \u017ce PHP jest j\u0119zykiem interpretowanym a kod PHP nie wymaga kompilacji, to developerzy przeprowadzaj\u0105 np. generacj\u0119 lub transformacj\u0119 kodu autoloadera. Doskona\u0142ym narz\u0119dziem s\u0142u\u017c\u0105cym do zautomatyzowania procesu budowy oprogramowania jest Apache Ant. To co r\u00f3\u017cni Ant i np.\u00a0 znany z Linuksa Make jest to, \u017ce Ant u\u017cywa plik\u00f3w w formacie XML do opisu procesu budowy &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/miro.borodziuk.eu\/index.php\/2018\/04\/11\/a\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;CI\/CD projekt\u00f3w PHP na Jenkinsie \u2013 Automatyzacja&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":2002,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[54],"tags":[],"_links":{"self":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/2032"}],"collection":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/comments?post=2032"}],"version-history":[{"count":20,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/2032\/revisions"}],"predecessor-version":[{"id":2114,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/2032\/revisions\/2114"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media\/2002"}],"wp:attachment":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media?parent=2032"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/categories?post=2032"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/tags?post=2032"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}