\division{OS Release Procedure}\label{section:ReleaseProcedure}

Several steps are necessary in order to prepare a successful release. We collect them here.


\subdivision{Release testing}\label{section:ReleaseTesting}

Before any release, make sure that the version you consider releasing passes a number of tests, as follows. 

\begin{itemize}

\item[1.] Run the {\tt nightlyBuild.py} script.

\item[2.] Do a {\tt make install}, then test the {\tt OSSolverService}. The tests are set up under the
assumption that this is done from the {\tt bin} directory. Switch into  the {\tt bin} directory and create a subfolder {\tt tmp} there in order to temporarily store the output.

\begin{itemize}
\item[a.] Test running a local solver,  
%(These examples assume that the {\tt OS/data} directory is one level above the directory  in which {\bf OSSolverService} is running. 
using in turn an OSiL, mps, and nl file.

\begin{verbatim}
OSSolverService -config ../OS/data/configFiles/testLocal.config
OSSolverService -config ../OS/data/configFiles/testLocalMPS.config
OSSolverService -config ../OS/data/configFiles/testLocalNL.config
\end{verbatim}

Each of these should produce an OSrL string that is displayed on the screen.
Look for {\tt <obj idx="-1">49920.55</obj>} in the first test, 
{\tt <obj idx="-1">-7667.94</obj>} in the second, 
and {\tt <obj idx="-1">7667.94</obj>} in the third.

\item[b.]  Test the service methods on the remote server.  

\noindent{\bf Step 1:} Test remote {\tt solve()} method for OSiL, mps, and nl files.

\begin{verbatim}
OSSolverService -config ../OS/data/configFiles/testRemote.config
OSSolverService -config ../OS/data/configFiles/testRemoteMPS.config
OSSolverService -config ../OS/data/configFiles/testRemoteNL.config
\end{verbatim}


You should get the OSrL for the simple test problem in each case. The optimal objective value
(the value of the tag {\tt <obj idx="-1">}) should be, respectively, 7668, $-$7667.94, and 7667.94.
%In all of these look for {\tt <obj idx="-1">-7667.94</obj>}.

\vskip 10pt


\noindent{\bf Step 2:} Test the remote {\tt getJobID()} method.


\begin{verbatim}
OSSolverService  -config ../OS/data/configFiles/testRemotegetJobID.config
\end{verbatim}



You will get a long jobID displayed on the screen.


\vskip 10pt


\noindent{\bf Step 3:} Test the remote {\tt send()} method. Use the {\tt send()} method with the jobID just  generated.  To do this open the file
\begin{verbatim}
/data/osolFiles/sendWithJobID.osol
\end{verbatim}
and replace the existing jobID with the one just generated.  Then run
\begin{verbatim}
OSSolverService  -config ../OS/data/configFiles/testRemoteSend.config
\end{verbatim}
The result should be ``send is true.''

\vskip 10pt

\noindent{\bf Step 4:} Test the remote {\tt knock()} method.  See if the  job is complete.


\begin{verbatim}
OSSolverService  -config ../OS/data/configFiles/testRemoteKnock.config
\end{verbatim}

You do not need to put in jobID information. The knock will get the status of all jobs. However, if you want just the status of the job you submitted put your jobID in the {\tt knock.osol} file. 

\vskip 10pt

\noindent{\bf Step 5:} Test the remote {\tt retrieve()} method. Get the result.

\begin{verbatim}
OSSolverService  -config ../OS/data/configFiles/testRemoteRetrieve.config
\end{verbatim}
Before executing this command make sure to put your jobID into the file {\tt retrieve.osol}.  
%Also, either delete the {\tt -browser} option or put in the path to your browser.
The result of the optimization will be put into a file called {\tt test.osrl} that will be in the {\tt tmp} folder in the directory in which you are running the {\tt OSSolverService.} 


{\bf IMPORTANT:}  Please do NOT commit the changes to these config files. 

 \end{itemize}


 
 \item[3.]  Test {\tt OSAmplClient}.  Although this can be run as a stand-alone application, it is designed to be called from  {\tt ampl}.  
 {\tt OSAmplClient}   gets installed in the {\tt bin} directory as a result of {\tt make install}. To make life easy, temporarily copy your {\tt ampl} executable into this {\tt bin} directory.   Also copy the test problem {\tt hs71.mod}  from {\tt OS/data/amplFiles/} into the {\tt bin} directory and run the test from there.   Do five tests, three local and two remote.
 
 
 \vskip 10pt
 
 
 {\bf Test 1:}  Inside  {\tt ampl} execute the following
 


\begin{verbatim}
model hs71.mod;
option solver OSAmplClient;
option OSAmplClient_options "solver xyz";
solve;
\end{verbatim}

The result should be an error saying:
\begin{verbatim}
<message>solver xyz is not supported</message>
\end{verbatim}
 
 \vskip 10pt
 
 {\bf Test 2:}  Inside  {\tt ampl} execute the following
 
\begin{verbatim}
model hs71.mod;
option solver OSAmplClient;
option OSAmplClient_options "solver ipopt";
solve;
display x3;
\end{verbatim}

The result of {\tt display x3} should be 3.82115. 


 \vskip 10pt
 
 {\bf Test 3:}  Inside  {\tt ampl} execute the following
 
\begin{verbatim}
model hs71.mod;
option solver OSAmplClient;
option OSAmplClient_options "solver cbc";
solve;
\end{verbatim}

You should get an error message saying:
\begin{verbatim}
<message>This COIN-OR Solver is not configured for nonlinear programming</message>
\end{verbatim}


\vskip 10pt

{\small
{\bf Test 4:}  Inside  {\tt ampl} execute the following
\begin{verbatim}
model hs71.mod;
option solver OSAmplClient;
option OSAmplClient_options "solver ipopt   serviceLocation        
    http://74.94.100.129:8080/OSServer/services/OSSolverService";
solve;
display x3;
\end{verbatim}
}%end small

The result of {\tt display x3} should be 3.82115. 


\vskip 10pt

{\small
{\bf Test 5:}  Inside  {\bf ampl} execute the following
\begin{verbatim}
model hs71.mod;
option solver OSAmplClient;
option OSAmplClient_options "solver clp  serviceLocation   
     http://74.94.100.129:8080/OSServer/services/OSSolverService";
solve;
\end{verbatim}
}%end \small

You should get an error message saying
\begin{verbatim}
<message>Clp cannot do nonlinear or quadratic or integer</message>
\end{verbatim}



There is a command script, {\tt testAmpl.run} in the directory {\tt OS/data/amplFiles} 
that contains the commands for all of these test. Simply start {\tt ampl} and execute
\begin{verbatim}
include testAmpl.run;
%\end{verbatim}

At this point you can delete the {\tt tmp} folder.

{\bf Note:} If any errors are encountered during these tests, it is possible to run {\tt OSAmplClient}
as a standalone using

\begin{verbatim}
./OSAmplClient hs71 <OSAmplClient_options>
\end{verbatim}

where {\tt <OSAmplClient\_options>} should be replaced by the options string of the relevant test.


\item[4.] Test the examples.  They are in the folder {\tt examples} in the COIN root directory. Be sure to follow the instructions in chapter~\ref{section:examples} for building these.

\begin{itemize}

\item[a.]  Connect to the {\tt algorithmicDiff} folder, and run {\tt make}. 
Execute {\tt ./OSAlgorithmicDiffTest}.  
This takes no arguments and will test a bunch of the AD routines.

\item[b.]  Connect to the {\tt branchCutPrice} folder, and run {\tt make}. 
Execute {\tt ./bcp}.  This takes no arguments.

\item[c.]  Connect to the {\tt cglCuts} folder, and run {\tt make}. 
Execute {\tt ./OSCglCuts}.  This takes no arguments.

\item[d.]  Connect to the {\tt instanceGenerator} folder, and run {\tt make}. 
Execute {\tt ./OSInstanceGenerator}.  This takes no arguments.

\item[e.]  Connect to the {\tt osModificationDemo} folder, and run {\tt make}. 
Execute {\tt ./OSModificationDemo}.  This takes no arguments.

\item[f.]  Connect to the {\tt osRemoteTest} folder, and run {\tt make}. 
Execute {\tt ./OSRemoteTest}.  This takes no arguments.

\item[g.]  Connect to the {\tt osResultDemo} folder, and run {\tt make}. 
Execute {\tt ./OSResultDemo}.  This takes no arguments.

\item[h.]  Connect to the {\tt osSolverDemo} folder, and run {\tt make}. 
Execute {\tt ./OSSolverDemo}.  This takes no arguments. The executable conducts five tests:
\begin{itemize}
\item[i.] A test of Clp using OSiL input. This problem should run to optimality and produce an objective of $-7667.941722$.
\item[ii.] A test of Cbc. This test uses solver options that force the solver to stop  on a time limit.
\item[iii.] A test of Couenne with input in .nl format. This test should run to optimality.
\item[iv.] A test of SYMPHONY. This test runs to optimality and reports an optimal objective value of~3089.
\item[v.] A test of Ipopt. This test stops at a locally optimal point with objective value 6.7279.
\item[vi.] A test of Bonmin. Solver options force this test to stop prematurely.
\end{itemize}

If all tests complete successfully, the last line of the output printed should read
\begin{verbatim}
SolverDemo COMPLETED WITHOUT ERROR
\end{verbatim}

\end{itemize}


\iffalse
\item[b.] Test the {\bf OSFileUpload} application.    Edit  {\bf OSFileUpload.cpp}. First comment out line 79 and then modify line 
\begin{verbatim}
osagent = new OSSolverAgent("http://******/os/servlet/OSFileUpload");
\end{verbatim}
to
{\small
\begin{verbatim}
osagent = new OSSolverAgent("http://gsbkip.chicagogsb.edu/os/servlet/OSFileUpload");
\end{verbatim}
}
Rebuild and run. This application takes one command line argument which is the file to be uploaded. 
\fi


\item[5.] Test the {\bf parsingTest} application, which makes sure that all the OSiL, OSoL and OSrL files behave as they should. Connect to the {\tt OS/applications/parsingTest} folder, and run {\tt make}.  Then execute the python script {\tt parsingTest.py} as follows:  

\begin{verbatim}
python  ./parsingTest.py ../../data/osilFiles
python  ./parsingTest.py ../../data/osolFiles
python  ./parsingTest.py ../../data/osrlFiles
\end{verbatim}

Each of these should produce a list of files, indicating a ``successful run'' for each of them. There is one exception, {\tt data/osolFiles/parsertestWithErrors.osol}, which should produce a list of error messages. These error messages can be checked against the contents of the file 
{\tt parsertestWithErrors.result}, which is also contained in the {\tt osolFiles}. (The python script may try to send this file to the OSoL parser, which will create further output diagnostics.)
\end{itemize}


\subdivision{Preparing the release}\label{section:ReleasePrep}

There are four scripts in the {\tt BuildTools} directory that help with the release, namely

\begin{verbatim}
prepare_new_stable
commit_new_stable
prepare_new_release
commit_new_release
\end{verbatim}

\medskip

The first of these, {\tt prepare\_new\_stable}, prepares a new stable version. The simplest form of invoking it is

\begin{verbatim}
($BUILDTOOLSDIR)/prepare_new_stable <loc>
\end{verbatim}

where {\tt loc} is the location on the svn server that forms the basis of the new stable version, e.g., {\tt OS/trunk}. (The leading {\tt https://projects.coin-or.org/svn/} can optionally be added.)
{\tt prepare\_new\_stable} uses svn to check out the code, making sure to locate the latest stable versions of all the dependencies, even if the basis uses trunk versions.

Some command line options (from comments in the script):

\begin{description}
  \item[\tt -p]			Suppress checkout (useful for testing)
  \item[\tt -m] 		Bump the major version number.
\end{description}

This script will do the following:

\begin{itemize}
  \item Set the new stable version number as the next minor version number in
    the current major version number. Use the {\tt -m} flag to bump the major
    version number.

  \item Convert externals from trunk to the top stable branch. Externals which
    are currently stable or release are left untouched. Use {\tt -t} to suppress
    the change from trunk to stable. The script {\tt set\_externals} is then invoked to set
    externals to stable versions where available.

  \item Check out externals. The BuildTools version used by externals (if any)
    is checked, and the script issues a warning if it doesn't match the
    version used by the source URL.

 \item Run the scripts to download any ThirdParty code.

  \item Run {\tt run\_autotools} to rebuild configure and make files.

  \item Run configure, make, and make test.

  \item Tweak the externals to upgrade trunk  dependencies to stable.
\end{itemize}

If there is any error during these tasks the script will stop and you should
examine the output.
   
\medskip

The script {\tt commit\_new\_stable} commits the new stable revision. It should be run only after 
{\tt prepare\_new\_stable} has been processed correctly.  

The simplest form of invoking it is

\begin{verbatim}
($BUILDTOOLSDIR)/commit_new_stable <loc>
\end{verbatim}

\noindent
where {\tt loc} is the location that forms the basis of the new stable version, e.g., {\tt OS/trunk}. In this form, it only performs a ``dry run'', that is, it only prints the commands that are to be executed, without actually doing anything. Once satisfied, use the command line parameter {\tt -c} to do the commit.



{\tt prepare\_new\_release} and {\tt commit\_new\_release} are the corresponding scripts to prepare and commit releases (which are based on stable versions).

Once a new release has been committed, it is customary to inform users of this fact by sending email to both {\tt OS@list.coin-or.org} and {\tt coin-announce@list.coin-or.org}.

If doing a maintenance release of an existing stable version (i.e., a release numbered {\tt x.y.n} with {\tt n} $>0$), the changes must be merged with the corresponding stable version {\tt x.y} first.
To do that, check out the stable version into a local directory and merge the appropriate trunk version into it, e.g.:

\begin{verbatim}
svn merge https://projects.coin-or.org/svn/OS/stable/2.8      \
               https://projects.coin-or.org/svn/OS/trunk@4678    .
\end{verbatim} 

Make sure to resolve any conflicts and commit the merged version.

After that, {\tt prepare\_new\_release} and {\tt commit\_new\_release}, as described just previously.
 

\subdivision{Version numbers}{\label{section:VersionNumbering}

The version number is defined in the file {\tt configure.ac}. There are actually two versions of this file,
in the root directory as well as the top OS directory. Each of them contains a call to {\tt AC\_INIT}, 
in which the second parameter is the version number. Change this number appropriately as follows:
For trunk versions, use {\bf trunk}, so that {\tt OSgetVersionNumber()} can print the correct svn revision number in the header of the output; for stable and release versions use the proper number ({\tt n.n} for stable versions, {\tt n.n.n} for releases).

Releases are numbered {\tt n.n.n}. 
If there are bug fixes only, the third digit is incremented. Feature changes lead to updating the second digit. If the API changes, update the first digit. Stable versions are numbered {\tt n.n}. The first two digits of the most current release correspond to the latest stable version. Thus if feature changes are implemented, a new stable version must also be prepared first.
