diff --git a/LoOPS_TeamCity.ipynb b/LoOPS_TeamCity.ipynb
index 2646c62..3e50b70 100644
--- a/LoOPS_TeamCity.ipynb
+++ b/LoOPS_TeamCity.ipynb
@@ -2,11 +2,11 @@
"cells": [
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 21,
"metadata": {
"ExecuteTime": {
- "end_time": "2018-01-08T23:20:39.306357Z",
- "start_time": "2018-01-08T23:20:39.297432Z"
+ "end_time": "2018-01-09T08:09:49.457463Z",
+ "start_time": "2018-01-09T08:09:49.451783Z"
},
"init_cell": true
},
@@ -52,8 +52,10 @@
"* Rich plugin ecosystem\n",
"* Really customizable system\n",
"* Not so complex...\n",
+ "* Updates so easy (Compared to redmine...)\n",
"* Mostly written in Java\n",
- "* Closed source :("
+ "* Closed source :(\n",
+ "* Limited to 100 build cfg & 3 agents "
]
},
{
@@ -143,10 +145,12 @@
"cell_type": "markdown",
"metadata": {
"slideshow": {
- "slide_type": "fragment"
+ "slide_type": "subslide"
}
},
"source": [
+ "# Vocabulary\n",
+ "\n",
"* **Build artifact**: a file or a folder produced during the build ( [example](https://hephaistos.lpp.polytechnique.fr/teamcity/overview.html) )"
]
},
@@ -154,6 +158,22 @@
"cell_type": "markdown",
"metadata": {
"slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "* **Meta-Runners**: a build config that has been extracted to make a template ( [example](https://hephaistos.lpp.polytechnique.fr/teamcity/admin/editProject.html?projectId=_Root&tab=metaRunner) )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
"slide_type": "slide"
}
},
@@ -209,6 +229,17 @@
"cell_type": "markdown",
"metadata": {
"slideshow": {
+ "slide_type": "subslide"
+ }
+ },
+ "source": [
+ "# LPP goals (What we want)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
"slide_type": "fragment"
}
},
@@ -220,6 +251,17 @@
"cell_type": "markdown",
"metadata": {
"slideshow": {
+ "slide_type": "fragment"
+ }
+ },
+ "source": [
+ "* Give users maximum freedom"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
"slide_type": "slide"
}
},
@@ -232,11 +274,15 @@
},
{
"cell_type": "markdown",
- "metadata": {},
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
"source": [
"# Available build agents\n",
"\n",
- "* Based on Docker cloud plugin\n",
+ "* Based on [Docker cloud plugin](https://plugins.jetbrains.com/plugin/9306-docker-cloud)\n",
"* Virtually anything that runs either inside **Docker** or **VirtualBox**(Vagrant)\n",
"* Spawn on demand\n",
"* For now **Windows**, **Linux**(Fedora, Ubuntu), **FreeBSD** and **Mac OSX** 10.12.2(Siera)\n"
@@ -250,13 +296,33 @@
}
},
"source": [
+ "# FreeBSD & Mac \n",
+ "\n",
+ "[meson@lpp](https://hephaistos.lpp.polytechnique.fr/teamcity/viewLog.html?buildId=6388&tab=buildLog&buildTypeId=mesonbuild_Build_2&logTab=tree&filter=all) [meson@travis](https://travis-ci.org/mesonbuild/meson/builds/325859215?utm_source=github_status&utm_medium=notification)\n",
+ "\n",
+ "[OSX agent](https://github.com/jeandet/teamcity-docker-agent-osx) [FreeBSD agent](https://github.com/jeandet/teamcity-docker-agent-freebsd)\n",
+ "\n",
+ "* Vagrant inside Docker\n",
+ "* Few txt files produces several GB machines\n",
+ "* Easy to deploy\n",
+ "* Hard to debug\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
"# I want to choose where I get built!\n",
"\n",
"**Team city introduce the notion of build requirements.**\n",
"\n",
- "- Agents expose [parameters](https://hephaistos.lpp.polytechnique.fr/teamcity/agentDetails.html?agentTypeId=72&tab=agentParameters)(<=> properties). [sources](https://github.com/jeandet/teamcity-docker-complete-agent/blob/master/Dockerfile#L36)\n",
+ "- Agents expose [parameters](https://hephaistos.lpp.polytechnique.fr/teamcity/agentDetails.html?agentTypeId=72&tab=agentParameters)(<=> properties). ( [sources](https://github.com/jeandet/teamcity-docker-complete-agent/blob/master/Dockerfile#L36) )\n",
"\n",
- "- So for each build config ones can declare some [requirements](https://hephaistos.lpp.polytechnique.fr/teamcity/admin/editRequirements.html?id=buildType:Miniphare_Build) that the agent has to match."
+ "- For each build config, ones can declare some [requirements](https://hephaistos.lpp.polytechnique.fr/teamcity/admin/editRequirements.html?id=buildType:Miniphare_Build) that the agent has to match to get spawned."
]
},
{
@@ -267,7 +333,13 @@
}
},
"source": [
- "# What about reports?\n"
+ "# What about reports?\n",
+ "\n",
+ "* As build artifact ( [LFR](https://hephaistos.lpp.polytechnique.fr/teamcity/viewLog.html?buildId=292&tab=artifacts&buildTypeId=LfrFlightSoftware_Build), [Hephaistos Web](https://hephaistos.lpp.polytechnique.fr/teamcity/project.html?projectId=HephaistosWeb&tab=projectOverview), [LibCDF](https://hephaistos.lpp.polytechnique.fr/teamcity/project.html?projectId=LibCDF&tab=projectOverview) )\n",
+ "* As Mail\n",
+ "* As slack message\n",
+ "* As stdout values ( [GStreamer Ninja](https://hephaistos.lpp.polytechnique.fr/teamcity/admin/editRunType.html?id=buildType:mesonbuild_GStreamerNightly&runnerId=RUNNER_69&cameFromUrl=%2Fteamcity%2Fadmin%2FeditBuildRunners.html%3Fid%3DbuildType%253Amesonbuild_GStreamerNightly%26init%3D1&cameFromTitle=) )\n",
+ "* As XML File ( [LibCDF GTest](https://hephaistos.lpp.polytechnique.fr/teamcity/admin/editBuildFeatures.html?id=buildType:LibCDF_Build) )"
]
},
{
@@ -278,7 +350,13 @@
}
},
"source": [
- "# API?"
+ "# Interactions with other tools\n",
+ "\n",
+ "* SonarQube ([example](https://sonarcloud.io/dashboard?id=sciqlop), [config](https://hephaistos.lpp.polytechnique.fr/teamcity/admin/editRunType.html?id=buildType:SciQLop_Build&runnerId=RUNNER_22&cameFromUrl=%2Fteamcity%2Fadmin%2FeditBuildRunners.html%3Fid%3DbuildType%253ASciQLop_Build%26init%3D1&cameFromTitle=))\n",
+ "* Slack ([example](https://sciqlop.slack.com/messages/C57HU1KBJ/), [config](https://hephaistos.lpp.polytechnique.fr/teamcity/slacknotifications/index.html?projectId=SciQLop))\n",
+ "* Github, Bitbucket, VS Team Services...\n",
+ "* Rhodecode ([Miniphare PR](https://hephaistos.lpp.polytechnique.fr/rhodecode/GIT_REPOSITORIES/LPP/phare/miniphare/miniphare/pull-request/410), [config](https://hephaistos.lpp.polytechnique.fr/teamcity/admin/editRunType.html?id=buildType:Miniphare_Build&runnerId=RUNNER_82&cameFromUrl=%2Fteamcity%2Fadmin%2FeditBuildRunners.html%3Fid%3DbuildType%253AMiniphare_Build%26init%3D1&cameFromTitle=))\n",
+ "* [VS IDE plugin](https://confluence.jetbrains.com/display/TCD10/Visual+Studio+Addin), [Eclipse plugin](https://confluence.jetbrains.com/display/TCD10/Eclipse+Plugin), [IntelliJ-based IDEs](https://blog.jetbrains.com/teamcity/2017/10/teamcity-integration-with-intellij-based-ides/)"
]
},
{
@@ -289,8 +367,62 @@
}
},
"source": [
- "# Time to play!"
+ "# API?\n",
+ "\n",
+ "* Quite easy to [understand](https://confluence.jetbrains.com/display/TCD10/REST+API) ( [buildTypes](https://hephaistos.lpp.polytechnique.fr/teamcity/app/rest/buildTypes/), [projects](https://hephaistos.lpp.polytechnique.fr/teamcity/app/rest/projects/) )\n",
+ "* Almost everything can be done through API"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "ExecuteTime": {
+ "end_time": "2018-01-09T08:37:54.802150Z",
+ "start_time": "2018-01-09T08:37:54.793474Z"
+ },
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import teamcity\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "# What Next?\n",
+ "\n",
+ "* Improve Rhodecode integration\n",
+ "* Boost agents startup time\n",
+ "* Switch to Docker swarm\n",
+ "* More Meta-Runners"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "slideshow": {
+ "slide_type": "slide"
+ }
+ },
+ "source": [
+ "# Questions?\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
diff --git a/teamcity.py b/teamcity.py
new file mode 100644
index 0000000..87b5329
--- /dev/null
+++ b/teamcity.py
@@ -0,0 +1,73 @@
+import requests
+import traceback
+import configparser
+from os.path import expanduser
+home = expanduser("~")
+
+class TeamCityJsonObject:
+
+ def __init__(self, json):
+ self.__dict__.update(json)
+
+ def __repr__(self):
+ return str(self.__dict__)
+
+
+class TeamCityProject(TeamCityJsonObject):
+
+ def __init__(self, json):
+ super(TeamCityProject, self).__init__(json)
+
+
+class TeamCityBuildType(TeamCityJsonObject):
+
+ def __init__(self, json):
+ super(TeamCityBuildType, self).__init__(json)
+
+class TeamCityBuild(TeamCityJsonObject):
+
+ def __init__(self, json):
+ super(TeamCityBuild, self).__init__(json)
+
+
+class TeamCityAPI:
+
+ def __init__(self, server, user, password):
+ self.server = server if '/app/rest' in server else server + '/app/rest'
+ self.session = requests.Session()
+ self.session.auth = (user, password)
+ self.session.headers.update({
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ })
+
+ def projects(self):
+ projects = self.session.get(
+ self.server + '/projects').json()
+ return [TeamCityProject(project) for project in projects['project']]
+
+ def build_types(self, project_id=None, project_name=None):
+ if project_id is not None:
+ url = self.server + '/projects/id:' + project_id + '/buildTypes'
+ elif project_name is not None:
+ url = self.server + '/projects/name:' + project_id + '/buildTypes'
+ else:
+ url = self.server + '/buildTypes'
+ build_types = self.session.get(url).json()
+ return [
+ TeamCityBuildType(build_type)
+ for build_type in build_types['buildType']
+ ]
+
+ def build_queue(self):
+ build_queue = self.session.get(tc.server+'/buildQueue').json()
+ return [
+ TeamCityBuild(build)
+ for build in build_queue['build']
+ ]
+
+config = configparser.ConfigParser()
+config.read(home+"/.teamcity.conf")
+
+
+tc = TeamCityAPI(config['DEFAULT']['server'], config['DEFAULT']['user'],config['DEFAULT']['password'])
\ No newline at end of file