Dashboard > CruiseControl > RunningCruiseControlAsaWindowsService
RunningCruiseControlAsaWindowsService Log In View a printable version of the current page.

Added by Robert Watkins , last edited by Kjersti Bjørnestad Berg on Sep 06, 2007  (view change)
Labels: 
(None)

README FIRST: In CruiseControl 2.6, the executable version comes with Windows service integration built in. 

Note In CruiseControl 2.7, the integrated Windows service is not by default set up to enable the CruiseControl Dashboard. To make it work you have to uninstall the service, edit wrapper.conf and cruisecontrol.bat as described below, and install the service again.

wrapper.conf
...
# Application parameters.  Add parameters as needed starting from 1
wrapper.app.parameter.1=CruiseControlWithJetty
wrapper.app.parameter.2=-jmxport
wrapper.app.parameter.3=8000
wrapper.app.parameter.2=-rmiport
wrapper.app.parameter.3=1099
wrapper.app.parameter.2=-webport
wrapper.app.parameter.3=8080
...

In cruisecontrol.bat, add the webapppath and webport arguments to the executable command.

This recipe shows you how to run Cruise control as a Windows service.

Three service wrappers are described

  1. JavaService
  2. JavaServiceWrapper
  3. AutoexNT

NOTE: many of the gotchas listed for JavaService also apply to JavaServiceWrapper, especially the notes on the user identity of the windows service.

NOTE 2: in recent CruiseControl distributions you can find the JavaServiceWrapper in the contrib/NtServiceWrapper directory.

NOTE 3: Even running as a service under a given username may cause problems. HOME is not defined
for the service under at least Windows XP which causes problems with CVS.


JavaService Recipe

Setting up

The first step is to obtain a service connector that hosts Java applications.

I found the Java Service tool from
http://www.multiplanconsultants.com/software/javaservice/downloads.html ideal as it was easy to host Cruise Control using it. The steps are:

  • Download and unpack the JavaService zip file
  • Rename JavaService.exe to CruiseControlService.exe. The Java Service guide suggests you should copy and rename for each java application you want to run as a service. This allows you to easily spot the Cruise Control service in the Windows task manager.
  • Place CruiseControlService.exe in the CruiseControl\bin directory
  • In the same directory make a copy of cruisecontrol.bat and name it cruisecontrolservice.bat
  • Edit cruisecontrolservice.bat and change the line:
    set EXEC=java -cp %CRUISE_PATH% CruiseControl %*






    to (all on one line):
    set EXEC=CruiseControlService.exe
        -install "Cruise Control" %JAVA_HOME%\jre\bin\hotspot\jvm.dll
        -Djava.class.path=%CRUISE_PATH%
        -start CruiseControl
        -params %*
        -out %CCDIR%\service_out.log
        -err %CCDIR%\service_err.log
        -current %CCDIR%





  • The above settings for the -out, -err and -current switches can be changed to suit your needs
  • You can choose to use another JVM such as %JAVA_HOME%\jre\bin\classic\jvm.dll
  • -current must point to the directory in which you have run the Cruise control project prior to starting the service. See below for details.
Enabling the Cruise Control web application using Jetty

The above configuration does not enable the Cruise Control web application. If you would like to enable the web application, follow the example above, but once you are editing the batch file, replace the line:

set EXEC="%JAVA_HOME%\bin\java" %CC_OPTS%
    -cp "%CRUISE_PATH%"
    -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder CruiseControlWithJetty %*
    -jmxport 8000








with (all on one line):
set EXEC=CruiseControlService.exe
-install "Cruise Control" %JAVA_HOME%\jre\bin\server\jvm.dll
-Djava.class.path=%CRUISE_PATH%
-Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder
-start CruiseControlWithJetty
-params %*
-jmxport 8000
-out %CCDIR%\service_out.log
-err %CCDIR%\service_err.log
-current %CCDIR%








If your JRE is in C:\Program Files\Java... or you install CruiseControl into C:\Program Files, you should notice that quote the items contains that path, for example:
set EXEC=CruiseControlService.exe
-install "Cruise Control" "%JAVA_HOME%\jre\bin\server\jvm.dll"
"-Djava.class.path=%CRUISE_PATH%"
-Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder
-start CruiseControlWithJetty
-params %*
-jmxport 8000
-out "%CCDIR%service_out.log"
-err "%CCDIR%service_err.log"
-current "%CCDIR%"








Authors (Enabling the Cruise Control web application using Jetty)
Allen Riddle (ariddle1@gmail.com) and Timothy Huertas (TimothyRHuertas@gmail.com)- 04/04/2006

Running the service
  • You must have run CruiseControl at least once from a DOS window to ensure that the project state (specifically the build label and last build date) has been saved to disk. The -current switch must point to the location where you ran the initial Cruise Control project.
  • Install the service by running the batch file with appropriate switches
    cruisecontrolservice.bat -configfile <name> [-port <port>]





  • Go to the Windows Services panel and locate the service "Cruise Control" and ensure that the service is running under the correct user account (see the gotcha section).
  • Set the service to "Automatic" and start it.
  • Check that the service is running correctly by looking at the output and error log files. The output file should have the same content that you see Cruise Control write to a console window.
  • Stop the service and restart it and recheck the logs to ensure that everything is still working.

That should be it. Your CruiseControl project should automatically start running whenever the machine is turned on. If you are having trouble the logs should help. However consult the gotcha section below for some additional pointers.

Enjoy!

Author: Tony Cook, tony at bci gb com - 16 March 2003

Gotchas

The biggest gotchas found so far are:

  • Ensuring the service is running under the correct account. If for example you are using CVS with SSH and RSA login certificates you WILL have to ensure that the service is running under the account for which the RSA key has been created. If you don't the SSH client will not find the key file and will attempt to prompt for a password. This just hangs the service and the service log indicates that the build has started but no further messages are seen. Running under the correct account is important also if you use other CVS authentication. In my case, using :pserver: I'd to login to CVS with my account and then make CruiseControl running under my own account. To make CruiseControl running with my account I had to change its properties from the Service Control Panel as JavaService, by default, installed it to run under the system account.
  • Ensuring that CruiseControl has been run at least once before starting the service. You can't use the service to set the -label or the -lastbuild switches as these values would be reset each time the service restarts. Not what you want.
  • Ensuring the working (current) directory of the service matches the directory where the bootstrap run of the Cruise Control project saved its persistent data. Check the -current switch used to install the service.
  • If the service won't start and you see errors in the Windows Application Log like "Could not find the service start class", you may need to change the value of CCDIR in cruisecontrolservice.bat to the explicit path to the cruise control directory. You'll need to remove the service (see below) and then re-install it to fix the problem.
  • Ensure that the JVM dll referenced in the batch file exists. The hotspot reference used in the example is not included in all distributions. Choose a JVM appropriate for your setup. If the dll is not found your service will stop immediately after start, without explanation. Other errors may also cause this behavior.
  • If you are using the -user and -password arguments to password-protect Cruise Control, your service will not install or protection will not become enabled. This is because JavaService uses these same arguments to assign what Windows user will run the service and therefore your .bat file will not run correctly. To get around this, recompile net\sourceforge\cruisecontrol\Main.java to accept different argument names like, for example, -jmxuser and -jmxpass.
Removing the Service

You will need to do this if you got the installation values wrong and you need to reinstall the service with new values, or you decide this doesn't work for you and you want shot of it.

  • Issue the DOS command (from CruiseControl\bin):
    CruiseControlService -uninstall "Cruise Control





You can also do this by hacking the registry if you know what you're doing, but this approach is not recommended.

Be warned that services sometimes do not get removed immediately. In this case, you will not be able to re-install the service straightaway. Why this is the case is a question for Microsoft to answer.

plink and SSH RSA issues

For those of you who are using plink and public/private keys, there are some quirks that may cause you some headaches. First, plink does not seem to recognize loaded keys from Pageant when running CruiseControl as a Windows service. There are some posts on the putty pages that seem to indicate unusual situations where plink and pageant do not communicate as well as one would like. If you are finding that your builds work fine using plink and pageant from the command console, but not as a Windows service, checkout the Gotchas above, and if that fails, check out these Gotchas:

More Gotchas
  • If you are creating a new user id that will be running your builds, it is essential that you login in as that user on the Windows box to initiate a SSH session to the machine you will be accessing. This is necessary so that you can answer the "SSH handshake" which allows you to interactively decide that the machine you are accessing is in fact that machine you want to access. Your windows registry will be updated and this Windows account will never be asked this question again. If you find that you are seeing messages in your service_err.log that look like this, this could be your problem:
    The servers host key is not cached in the registry. You have
    no guarantee that the server is the computer you think it is.





Once you have completed this handshake make sure to use that same user as the Windows service account. For more information this link will explain the reason for the "SSH handshake". http://the.earth.li/~sgtatham/putty/0.53b/htmldoc/Chapter2.html#2.2

  • Since there are issues with plink communicating with pageant when running CruiseControl as a service (this problem does not exist when running CruiseControl under a command prompt) pageant needs to be taken out of the loop. One option is to create batch file which launches plink.exe with additional "connection" parameters such as your private key, passphrase, and server name.

Examples:

  • Using key with passphrase:
    <path to plink>\plink.exe -v -ssh -P <port> -pw <passphrase> -i
        <path to private key>\<private key name> %*





  • Using key with no passphrase:
    <path to plink>\plink.exe -v -ssh -P <port> -i
        <path to private key>\<private key name> %*





  • Using no key, just user and password:
    <path to plink>\plink.exe -v -ssh -pw <password> -P <port> %*





To understand all the available options for plink just launch plink.exe at a command prompt, the options listed and explained quite well. This bat file essentially "intercepts" the direct call to plink.exe and tosses on a few more parameters, those that would normally be picked up from pageant (the private key!). After you get everything working, you can remove the "-v" option from the batch file, which will shorten the service_err.log file. Of note is the "-pw" and "-i" options, password / passphrase and private key respectively. If you have a private with a passphrase, then you need both, but if you are not using keys (which I would recommend against, given the benefits of using keys and the relative ease of setting them up) then you don't need the private key option.

Important Points

  • Make sure you update your CVS_RSH environment variable to point to the plink.bat file, instead of plink.exe
  • %* must be at the end of your bat file, so that commands will get passed on (only tested with CVS). It is important to point out the reason you did not need to specify the "-l <user>" or "<server>" in the plink.bat file, is that these are %1 - %3 in the %* argument list. These arguments are retrieved from the CVSROOT variable and passed along, so there is no need to hard code them in the plink.bat file, in fact it would cause issues if plink.exe is called with user and server twice.

At this point you are ready to run the "Cruise Control" service. Check out the service_err.log for connection issues, the "-v" option added in the plink.bat file will help immensely in troubleshooting errors as verbose SSH messages will be logged.

Overall Drawbacks

  • The passphrase is hardcoded in a bat file, Argh! This negates the value of encryption for your private key. In this case you may choose to generate your keys without passphrases and you can remove the -pw option. http://www.tartarus.org/~simon/puttydoc/Chapter8.html#8 (for more information)
  • Using the plink.bat file did not work with Eclipse ext connections. So for those of you who have Eclipse running during the day and are also functioning as a build server, there are no issues with accessing plink.exe from Eclipse and running pageant to load your keys. Eclipse does not care about the CVS_RSH variable anyways. Eclpise has a place to enter that value anyways.

Author: Jason Trust, jtrust at ctpartners.com - 12 February, 2004


JavaServiceWrapper Recipe

I have been running CruiseControl as a JavaServiceWrapper service for the last 6 months with the following wrapper.conf file. Hope it helps....

FYI I put the wrapper.jar and the wrapper.dll in the same lib directory as all the cruise control jars.

Cheers,
MC

(see http://wrapper.tanukisoftware.org/doc/english/index.html)

#********************************************************************
# Wrapper Properties
#********************************************************************
# Java Application
wrapper.java.command=java

# Java Main class
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp

# Java Classpath (include wrapper.jar)  Add class path elements as
#  needed starting from 1
wrapper.java.classpath.1=C:/cruisecontrol-2.1.5/main/lib/*.jar
wrapper.java.classpath.2=C:/jakarta-ant-1.5.1/lib/*.jar
wrapper.java.classpath.3=C:/cruisecontrol-2.1.5/main/dist/cruisecontrol.jar
wrapper.java.classpath.4=C:/j2sdk1.4.1_01/lib/*.jar

# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=C:/cruisecontrol-2.1.5/main/lib

# Java Additional Parameters
#wrapper.java.additional.1=

# Initial Java Heap Size (in MB)
wrapper.java.initmemory=3

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=64

# Application parameters.  Add parameters as needed starting from 1
wrapper.app.parameter.1=CruiseControl
wrapper.app.parameter.2=-port
wrapper.app.parameter.3=8000

# Port which the native wrapper code will attempt to connect to
wrapper.port=1777

#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM

# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=../logs/wrapper.log

# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO

# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=10m

# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=10

# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=ERROR

#********************************************************************
# Wrapper NT Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
#  using this configuration file has been installed as a service.
#  Please uninstall the service before modifying this section.  The
#  service can then be reinstalled.

# Name of the service
wrapper.ntservice.name=CruiseControl

# Display name of the service
wrapper.ntservice.displayname=CruiseControl Service (v2.1.5)

# Description of the service
wrapper.ntservice.description=Continuous integration builds \
and tests with JUnit, Ant and CruiseControl.

# Service dependencies.  Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=

# Mode in which the service is installed.  AUTO_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START

# Priority at which the service is run.  NORMAL, LOW, HIGH, or
#  REALTIME
wrapper.ntservice.process_priority=NORMAL

# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false








Author - Mike Cassisa mcassisa at drs-tsi com - Feb 26th 2004
The version provided in the distribution didn't allow the jmx console to work properly for me as it missed this line :
# Java Additional Parameters
wrapper.java.additional.1=-Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder




Maybe it should be added in the distribution.
Author - Michel Rasschaert - 23/12/2004
Including Michel's line above, I added 3 lines in total to wrapper.conf to enable the jmx console. I believe the cruise control version used was 2.1.5, though don't hold me to that.
# Java Additional Parameters
wrapper.java.additional.1=-Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder

# Specify the jmx port
wrapper.app.parameter.4=-port
wrapper.app.parameter.5=8000

NB. In later versions of cruise control, I believe the '-port' argument has had its name changed to '-jmxport'.
Author - Eliot Sykes - April 17th 2007 


AutoexNT

AutoexNT (http://support.microsoft.com/kb/q243486/) lets you run programs at windows startup time.
The installation procedure is very simple (see web page).

I just added the line:

start /b /dc:\apps\cruisecontrol cmd /c cruisecontrol.bat








to Autoexnt.bat and CruiseControl is up and running.
Author: Miki Tebeka <mtebeka@qualcomm.com> (Feb 14, 2006)

Ok, I just tried all three methods with CruiseControl-2.5 (april) and wanted to share some more gotchas that aren't listed above.
First, it's important to note that the AutoExNT service is not a true service. I wasn't able to start and stop my cc instance normally. I'm sure there's an easier way to do it but I actually had to restart my server to stop my cc instance. For the wrapper.exe and the JavaService.exe methods, I think it's important to note that you can't have spaces in your paths (eg. Java Home in Program Files). I also had to escape my backslashes but you could probably use quotes to handle these problems as well. Also, if you have a different directory for cchome, just remember that you need to have the lib, logs and webapp directory there for everything to work (You can modify the web.xml for the logs directory). Lastly, I found, with the JavaService.exe, I had to specify my parameters external to the batch file to get it to work and I had to explicitly specify the jmxport of 8000. For some reason, it wasn't picking up the default jmxport. Below is my CruiseControlService.bat in case you're interested:

@echo off

REM ################################################################################
REM # CruiseControl, a Continuous Integration Toolkit
REM # Copyright (c) 2001, ThoughtWorks, Inc.
REM # 651 W Washington Ave. Suite 600
REM # Chicago, IL 60661 USA
REM # All rights reserved.
REM #
REM # Redistribution and use in source and binary forms, with or without
REM # modification, are permitted provided that the following conditions
REM # are met:
REM #
REM # + Redistributions of source code must retain the above copyright
REM # notice, this list of conditions and the following disclaimer.
REM #
REM # + Redistributions in binary form must reproduce the above
REM # copyright notice, this list of conditions and the following
REM # disclaimer in the documentation and/or other materials provided
REM # with the distribution.
REM #
REM # + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
REM # names of its contributors may be used to endorse or promote
REM # products derived from this software without specific prior
REM # written permission.
REM #
REM # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
REM # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
REM # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
REM # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
REM # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
REM # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
REM # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
REM # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
REM # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
REM # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
REM # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REM ################################################################################

REM Set this if you're using SSH-based CVS
REM set CVS_RSH=

REM Uncomment the following line if you have OutOfMemoryError errors
REM set CC_OPTS=-Xms128m -Xmx256m

REM The root of the CruiseControl directory. The key requirement is that this is the parent
REM directory of CruiseControl's lib and dist directories.
REM By default assume they are using the batch file from the local directory.
REM Acknowledgments to Ant Project for this batch file incantation
REM %~dp0 is name of current script under NT
set CCDIR=%~dp0
REM set CCDIR=D:\builds

:setClassPath
set CRUISE_PATH=

:checkJava
if not defined JAVA_HOME goto noJavaHome
set CRUISE_PATH=C:
"Program Files"\\Java\\jdk1.5.0_06\\lib
tools.jar
goto setCruise

:noJavaHome
echo Warning: You have not set the JAVA_HOME environment variable. Any tasks relying on the tools.jar file (such as <javac>) will not work properly.

:setCruise
set LIBDIR=%CCDIR%
lib

set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
cruisecontrol.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
log4j.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
jdom.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
ant.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
ant-launcher.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
jasper-compiler.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
jasper-runtime.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
xercesImpl-2.8.0.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
xml-apis-2.8.0.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
xmlrpc-2.0.1.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
xalan-2.7.0.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
serializer-2.7.0.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
jakarta-oro-2.0.3.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
mail.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
junit.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
activation.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
commons-net-1.1.0.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
starteam-sdk.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
mx4j.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
mx4j-tools.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
mx4j-remote.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
smack.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
comm.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
x10.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
fast-md5.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
maven-embedder-2.0.3-dep.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
javax.servlet.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
org.mortbay.jetty.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
commons-logging.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
commons-el.jar
set CRUISE_PATH=%CRUISE_PATH%;%LIBDIR%
jaxen-1.1-beta-8.jar
set CRUISE_PATH=%CRUISE_PATH%;.

set EXEC=CruiseControlService.exe -install "Cruise Control" C:
"Program Files"\\Java\\jdk1.5.0_06\\jre\\bin\\server
jvm.dll -Djava.class.path=%CRUISE_PATH% -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder -start CruiseControlWithJetty -params %* -out D:\\Programs\\CruiseControl-2.5\\logs
service_out.log -err D:\\Programs\\CruiseControl-2.5\\logs
service_err.log -current D:\\Programs
CruiseControl-2.5

  1. set EXEC="%JAVA_HOME%\bin\java" %CC_OPTS% -cp "%CRUISE_PATH%" #-Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder # CruiseControlWithJetty %* #-jmxport 8000 -rmiport 2099
    echo %EXEC%
    %EXEC%
Powered by a free Atlassian Confluence Open Source Project / Non-profit License granted to ThoughtWorks, Inc.. Evaluate Confluence today.
Powered by Atlassian Confluence 2.7.1, the Enterprise Wiki. Bug/feature request - Atlassian news - Contact administrators