mercure 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b85cc795a9b1d7c44d3ae394f9cab03c92c37c0b
4
+ data.tar.gz: d3eb4e46091076619a7be52340218b8a31074e02
5
+ SHA512:
6
+ metadata.gz: 7bba4528c9442b52fad452b1f161c7156fcb82893eb516a5dfb7cdc169be0a2d7dac51e8868c1ce016b6e260e720465819fffc38a40b43e700090d64e0897c4d
7
+ data.tar.gz: 2c8c507724f85c656cf148ccf79767e6cdb8854df439943c4e8153d5d0005f760c2911dfe21a3ce39ea6296cb617472c06ae8fda7383b0da122f33347a03fade
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ # YARD artifacts
19
+ .yardoc
20
+ _yardoc
21
+ doc/
22
+ **/.DS_Store
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mercure.gemspec
4
+ gemspec
5
+
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 teriiehina
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,71 @@
1
+ mercure
2
+ ======
3
+
4
+ Simple tool to build and deploy iOS apps
5
+
6
+ # Not usable
7
+
8
+ Be very careful. `mercure` is not intended to be used yet. Neither in production nor development.
9
+ This repo is for collaboration for a tool in its very first iteration.
10
+
11
+ Wet paint, you've been warned.
12
+
13
+ # What mercure should do
14
+
15
+ In french for now, translation coming soon.
16
+
17
+ mercure est une gem ruby
18
+
19
+ mercure ne prend en paramètre qu'un fichier plist
20
+
21
+ mercure se lance dans un repo git clean et le laisse clean à la fin
22
+
23
+ mercure est toujours lancé depuis le répertoire qui contient le xcworkspace ou le xccodeproj
24
+
25
+ mercure part du principe que
26
+
27
+ - dans le cas d'une livraison versionnée, c'est une nouvelle version
28
+ - l'on peut se connecter en ssh password-less sur le serveur d'upload
29
+ - qu'on peut accéder au repo 'origin' pour envoyer les tags en fin de livraison
30
+
31
+ mercure pourra soumettre à Apple
32
+
33
+ A la fin de la livraison, mercure taggue le job en fonction du nom et de la version
34
+
35
+ voir comment unlocker le keychain (regarder du côté de visudo)
36
+
37
+ Le plist indique
38
+
39
+ - les paths (qui sont toujours relatif au dossier depuis lequel on lance mercure):
40
+ - le path vers le Info.plist
41
+
42
+ - la compilation
43
+ - le nom du projet ou du workspace
44
+ - le scheme ou la target à builder
45
+ - le targetSDK
46
+ - la configuration de build (Debug , Release)
47
+ - l'identité et le profil de signature
48
+
49
+ - un dictionnaire dont les "clés/valeurs" sont copiées automatiquement dans le Info.plist
50
+
51
+ - tous les paramètre de build
52
+ - bundle id
53
+ - environnement du cimob
54
+
55
+ - le chemin des icones à modifier
56
+
57
+ - si la livraison est versionnée ou pas
58
+
59
+ - si on modifie l'icone ou pas
60
+
61
+ - pour l'upload des ressources (ipa, plist et dsym) générées:
62
+ - l'ip ou l'url du serveur
63
+ - le login ssh
64
+ - le path local sur le serveur
65
+ - l'url publique
66
+
67
+ - si on tagge le job
68
+
69
+
70
+ Expliciter les valeurs par défaut
71
+ Mieux définir les noms des fichiers générés
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'mercure'
6
+
7
+ Mercure::Mercure.start(ARGV)
@@ -0,0 +1,42 @@
1
+ require "mercure/version"
2
+ require 'thor'
3
+ require 'plist'
4
+
5
+ require 'mercure/deploy'
6
+
7
+ module Mercure
8
+
9
+ class Mercure < Thor
10
+
11
+ desc "check", "will check if everything necessary for building easily is present"
12
+ def check
13
+ puts "checking. Missing tools will be installed, if possible."
14
+
15
+ end
16
+
17
+ desc "build JOB", "will build the job"
18
+ def build(plist)
19
+ buildDeployments plist
20
+ end
21
+
22
+ desc "upload JOB", "will upload the job (must have been 'build' before)"
23
+ def upload(plist)
24
+ uploadDeployments plist
25
+ end
26
+
27
+ desc "deploy JOB", "will deploy the job (must have been 'build' and 'upload' before)"
28
+ def deploy(plist)
29
+ deployDeployments plist
30
+ end
31
+
32
+ desc "pan JOB", "will build, upload and deploy the job"
33
+ def pan(plist)
34
+ panDeployments plist
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
41
+
42
+
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'plist'
5
+
6
+ def buildApp (settings)
7
+
8
+ applicationName = settings[:applicationName]
9
+ projectDirectory = settings[:projectDirectory]
10
+
11
+ workspaceName = settings[:workspaceName]
12
+ schemeName = settings[:schemeName]
13
+ targetSDK = settings[:targetSDK]
14
+
15
+ buildConfiguration = settings[:buildConfiguration]
16
+ buildDirectory = settings[:buildDirectory]
17
+
18
+ puts "Compilation de l'application #{applicationName}"
19
+
20
+ build_command = "xcodebuild"
21
+ build_command += " -workspace \"#{workspaceName}\""
22
+ build_command += " -scheme \"#{schemeName}\""
23
+ build_command += " -configuration #{buildConfiguration}"
24
+ build_command += " BUILD_DIR=\"#{buildDirectory}\""
25
+ build_command += " BUILD_PRODDUCTS_DIR=\"#{buildDirectory}\"/#{buildConfiguration}-iphoneos"
26
+ build_command += " TARGET_BUILD_DIR=\"#{buildDirectory}\"/#{buildConfiguration}-iphoneos"
27
+ build_command += " CONFIGURATION_BUILD_DIR=\"#{buildDirectory}\"/#{buildConfiguration}-iphoneos"
28
+ build_command += " clean build"
29
+ build_command += " | tee \"#{buildDirectory}/xcodebuild.log\""
30
+ build_command += " | xcpretty -c --report html"
31
+
32
+ puts build_command
33
+
34
+ Dir.chdir "#{projectDirectory}"
35
+ system("#{build_command}")
36
+
37
+ end
38
+
39
+ def updateBuild (settings)
40
+
41
+ # updateIcon settings , settings[:deploy]
42
+
43
+ projectInfosPath = plistInAppPath(settings)
44
+
45
+ puts "Mise-à-jour du fichier #{projectInfosPath}"
46
+
47
+ # projectInfos = Plist::parse_xml(projectInfosPath)
48
+
49
+ plist = CFPropertyList::List.new(file: projectInfosPath)
50
+ projectInfos = CFPropertyList.native_types(plist.value)
51
+
52
+ settings[:deploy]["infosPlist"].each do |key , value|
53
+ projectInfos[key] = value
54
+ end
55
+
56
+ # ajout du SHA1 du commit servant à builder cette version
57
+ projectInfos["lastCommitSHA1"] = settings[:gitSHA1]
58
+
59
+
60
+ plist.value = CFPropertyList.guess(projectInfos)
61
+ plist.save(projectInfosPath , CFPropertyList::List::FORMAT_BINARY)
62
+
63
+ end
64
+
@@ -0,0 +1,130 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'plist'
5
+ require 'parse-ruby-client'
6
+
7
+ require 'cfpropertylist'
8
+
9
+ require_relative 'settings.rb'
10
+ require_relative 'update_icon.rb'
11
+ require_relative 'build.rb'
12
+ require_relative 'plist.rb'
13
+ require_relative 'ipa.rb'
14
+ require_relative 'parse.rb'
15
+ require_relative 'paths.rb'
16
+ require_relative 'git.rb'
17
+ require_relative 'upload.rb'
18
+
19
+
20
+ def buildDeployments (plist)
21
+
22
+ deployments = Plist::parse_xml(plist)
23
+
24
+ deployments.each do |deploy|
25
+
26
+ puts "Chargement des variables"
27
+ settings = load_settings deploy
28
+
29
+ # on s'assure d'être dans la bonne version du code
30
+ # si le Info.plist ne contient pas de valeur pour la clé
31
+ # :CFBundleVersion (ce qui serait un peu embetant)
32
+ # on taggue le commit courant
33
+ checkOutGitVersion settings
34
+
35
+ puts "Création de l'.app"
36
+ buildApp settings
37
+ updateBuild settings
38
+
39
+ puts "Création de l'.ipa et du .plist"
40
+ buildArtefacts settings
41
+ end
42
+
43
+ end
44
+
45
+ def uploadDeployments (plist)
46
+
47
+ deployments = Plist::parse_xml(plist)
48
+
49
+ deployments.each do |deploy|
50
+ puts "Chargement des variables"
51
+ settings = load_settings deploy
52
+
53
+ puts "Téléversement de l'.ipa et du .plist"
54
+ uploadArtefacts settings
55
+ end
56
+
57
+ end
58
+
59
+ def deployDeployments (plist_path)
60
+
61
+ plist_content = CFPropertyList::List.new(file: plist_path)
62
+ deployments = CFPropertyList.native_types(plist_content.value)
63
+
64
+ deployments.each do |deploy|
65
+ puts "Chargement des variables"
66
+ settings = load_settings deploy
67
+
68
+ puts "Mise à jour de Parse"
69
+ objectId = updateParse settings
70
+ deploy["parse"]["objectId"] = objectId
71
+ end
72
+
73
+ puts "sauvegardes des infos de parse"
74
+ plist_content.value = CFPropertyList.guess(deployments)
75
+ plist_content.save(plist_path , CFPropertyList::List::FORMAT_XML)
76
+
77
+ end
78
+
79
+ def panDeployments (plist)
80
+
81
+ deployments = Plist::parse_xml(plist)
82
+
83
+ deployments.each do |deploy|
84
+
85
+ puts "Chargement des variables"
86
+ settings = load_settings deploy
87
+
88
+ # on s'assure d'être dans la bonne version du code
89
+ # si le Info.plist ne contient pas de valeur pour la clé
90
+ # :CFBundleVersion (ce qui serait un peu embetant)
91
+ # on taggue le commit courant
92
+ checkOutGitVersion settings
93
+
94
+ puts "Création de l'.app"
95
+ buildApp settings
96
+ updateBuild settings
97
+
98
+ puts "Création de l'.ipa et du .plist"
99
+ buildArtefacts settings
100
+
101
+ if should_upload
102
+ puts "Téléversement de l'.ipa et du .plist"
103
+ uploadArtefacts settings
104
+
105
+ puts "Mise à jour de Parse"
106
+ updateParse settings
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+
114
+
115
+ def buildArtefacts (xcode_settings)
116
+ generateIpa xcode_settings
117
+ generatePlist xcode_settings
118
+ end
119
+
120
+ # def unlock_keychain
121
+ # current_user = `whoami`
122
+ #
123
+ # keychainFilePath = "/Users/jenkins/Library/Keychains/login.keychain"
124
+ # keychainPassword = "j3nk1n5"
125
+ #
126
+ # puts("Dévérouillage du keychain en vue de la génération de l\'ipa")
127
+ # system("security unlock-keychain -p #{keychainPassword} #{keychainFilePath}")
128
+ # end
129
+
130
+
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ def checkOutGitVersion (settings)
5
+
6
+ tags = `git tag`
7
+ tag_name = settings[:CFBundleVersion]
8
+ current_commit = settings[:gitSHA1]
9
+
10
+ if tags.include?("#{tag_name}\n") == false
11
+ puts "Le tag #{tag_name} n'existe pas."
12
+ puts "Nous allons le créer pour pointer vers le commit actuel (#{current_commit})"
13
+
14
+ create_tag = `git tag #{tag_name}`
15
+ end
16
+
17
+ puts "On checkout le tag #{tag_name}"
18
+ co_tag = `git checkout #{tag_name}`
19
+ end
20
+
21
+ def tagGit (settings)
22
+
23
+ tag_name = settings[:CFBundleVersion]
24
+ current_commit = settings[:gitSHA1]
25
+
26
+ # si le tag existe déjà on l'efface
27
+ tags = `git tag`
28
+
29
+ if tags.include?("#{tag_name}\n")
30
+ puts "Le tag #{tag_name} existe déjà."
31
+ puts "Nous allons le faire pointer vers le commit actuel (#{current_commit})"
32
+
33
+ delete_tag = `git tag -d #{tag_name}`
34
+ end
35
+
36
+ create_tag = `git tag #{tag_name}`
37
+
38
+ end
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'plist'
5
+ require 'parse-ruby-client'
6
+
7
+ require_relative 'paths.rb'
8
+
9
+ def generateIpa settings
10
+
11
+ buildDirectory = settings[:buildDirectory]
12
+ buildConfiguration = settings[:buildConfiguration]
13
+ buildNumber = settings[:buildNumber]
14
+ applicationName = settings[:applicationName]
15
+
16
+ appPath = appPath(settings)
17
+ ipaPath = ipaPath(settings)
18
+
19
+ dsymPath = dsymPath(settings)
20
+ savedDsymPath = savedDsymPath(settings)
21
+ zippedDsymPath = zippedDsymPath(settings)
22
+
23
+ signingIdentity = settings[:signingIdentity]
24
+ provisioningProfile = settings[:provisioningProfile]
25
+
26
+ puts "Construction de l'IPA"
27
+
28
+ signingCommand = "/usr/bin/xcrun -sdk iphoneos PackageApplication"
29
+ signingCommand += " -v \"#{appPath}\""
30
+ signingCommand += " -o \"#{ipaPath}\""
31
+ signingCommand += " --sign \"#{signingIdentity}\""
32
+ signingCommand += " --embed \"#{provisioningProfile}\""
33
+ signingCommand += " | tee \"#{settings[:buildDirectory]}/PackageApplication.log\""
34
+
35
+
36
+ puts signingCommand
37
+ system signingCommand
38
+
39
+ system("rm -f \"#{savedDsymPath}\"")
40
+ system("cp -R \"#{dsymPath}\" \"#{savedDsymPath}\"")
41
+ system("zip -r \"#{zippedDsymPath}\" \"#{savedDsymPath}\"")
42
+
43
+ end
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'plist'
5
+ require 'parse-ruby-client'
6
+
7
+ require_relative 'paths.rb'
8
+
9
+ def updateParse (settings)
10
+
11
+ Parse.init application_id: settings[:deploy]["parse"]["appId"],
12
+ api_key: settings[:deploy]["parse"]["apiKey"]
13
+
14
+ parseInfos = settings[:deploy]["parse"]
15
+
16
+ objectId = parseInfos["objectId"]
17
+
18
+ if (objectId.nil? or objectId.length == 0)
19
+ appVersion = Parse::Object.new("ApplicationVersion")
20
+ else
21
+ puts "On a déjà déployé cette version, on la met à jour"
22
+ appVersionsQuery = Parse::Query.new("ApplicationVersion")
23
+ appVersionsQuery.eq("objectId", objectId)
24
+ appVersion = appVersionsQuery.get.first
25
+ end
26
+
27
+ appVersion["applicationId"] = parseInfos["applicationId"]
28
+ appVersion["versionNumber"] = parseInfos["versionNumber"]
29
+ appVersion["versionChangeLog"] = parseInfos["versionChangeLog"]
30
+ appVersion["versionLevel"] = parseInfos["versionLevel"].to_i
31
+ appVersion["versionUrl"] = publicPlistURL settings
32
+
33
+ result = appVersion.save
34
+
35
+ if (objectId.nil? or objectId.length == 0)
36
+ puts "le déploiement a été créée"
37
+ else
38
+ puts "le déploiement a bien été mis à jour"
39
+ end
40
+
41
+ result["objectId"]
42
+
43
+ end
44
+
@@ -0,0 +1,170 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ #
5
+ # Application
6
+ #
7
+
8
+ def appPath (settings)
9
+
10
+ buildDirectory = settings[:buildDirectory]
11
+ buildConfiguration = settings[:buildConfiguration]
12
+ buildNumber = settings[:buildNumber]
13
+ bundleName = settings[:bundleName]
14
+
15
+ "#{buildDirectory}/#{buildConfiguration}-iphoneos/#{bundleName}.app"
16
+
17
+ end
18
+
19
+ #
20
+ # IPA
21
+ #
22
+
23
+ def ipaName (settings)
24
+
25
+ buildDirectory = settings[:buildDirectory]
26
+ buildConfiguration = settings[:buildConfiguration]
27
+ buildNumber = settings[:buildNumber]
28
+ applicationName = settings[:applicationName]
29
+
30
+ pjServerConf = settings[:deploy]["infosPlist"]["PJServerConf"]
31
+
32
+ "#{applicationName}.#{buildNumber}.ipa"
33
+
34
+ end
35
+
36
+ def ipaPath (settings)
37
+
38
+ buildDirectory = settings[:buildDirectory]
39
+ buildConfiguration = settings[:buildConfiguration]
40
+ buildNumber = settings[:buildNumber]
41
+ applicationName = settings[:applicationName]
42
+ ipaName = ipaName(settings)
43
+
44
+ "#{buildDirectory}/#{buildConfiguration}-iphoneos/#{ipaName}"
45
+
46
+ end
47
+
48
+ def remoteIpaPath (settings , destination)
49
+
50
+ ipaName = ipaName(settings)
51
+ remotePath = destination["path"]
52
+
53
+ "#{remotePath}/#{ipaName}"
54
+
55
+ end
56
+
57
+
58
+ #
59
+ # Plist
60
+ #
61
+
62
+ def plistInAppPath (settings)
63
+
64
+ buildDirectory = settings[:buildDirectory]
65
+ buildConfiguration = settings[:buildConfiguration]
66
+ bundleName = settings[:bundleName]
67
+
68
+ "#{buildDirectory}/#{buildConfiguration}-iphoneos/#{bundleName}.app/Info.plist"
69
+ end
70
+
71
+ def deployPlistPath (settings)
72
+
73
+ buildDirectory = settings[:buildDirectory]
74
+ buildConfiguration = settings[:buildConfiguration]
75
+ buildNumber = settings[:buildNumber]
76
+ applicationName = settings[:applicationName]
77
+ plistName = plistName settings
78
+
79
+ "#{buildDirectory}/#{buildConfiguration}-iphoneos/#{plistName}"
80
+
81
+ end
82
+
83
+ def remoteDeployPlistPath (settings , destination)
84
+
85
+ remotePath = destination["path"]
86
+ plistName = plistName (settings)
87
+
88
+ "#{remotePath}/#{plistName}"
89
+
90
+ end
91
+
92
+ def plistName (settings)
93
+
94
+ applicationName = settings[:applicationName]
95
+ pjServerConf = settings[:deploy]["infosPlist"]["PJServerConf"]
96
+ buildNumber = settings[:buildNumber]
97
+
98
+ "#{applicationName}.#{buildNumber}.plist"
99
+
100
+ end
101
+
102
+ def publicPlistURL (settings)
103
+
104
+ publicURL = settings[:deploy]["uploadServer"]["plist"][0]["publicURL"]
105
+ plistName = plistName (settings)
106
+
107
+ "#{publicURL}/#{plistName}"
108
+
109
+ end
110
+
111
+ #
112
+ # Dsym
113
+ #
114
+
115
+ def dsymPath (settings)
116
+
117
+ buildDirectory = settings[:buildDirectory]
118
+ buildConfiguration = settings[:buildConfiguration]
119
+ bundleName = settings[:bundleName]
120
+
121
+ "#{buildDirectory}/#{buildConfiguration}-iphoneos/#{bundleName}.app.dSYM"
122
+
123
+ end
124
+
125
+ def savedDsymPath (settings)
126
+
127
+ buildDirectory = settings[:buildDirectory]
128
+ buildConfiguration = settings[:buildConfiguration]
129
+ buildNumber = settings[:buildNumber]
130
+ applicationName = settings[:applicationName]
131
+
132
+ "#{buildDirectory}/#{buildConfiguration}-iphoneos/#{applicationName}.#{buildNumber}.app.dSYM"
133
+
134
+ end
135
+
136
+ def zippedDsymPath (settings)
137
+
138
+ savedDsymPath(settings) + ".zip"
139
+
140
+ end
141
+
142
+ def remoteDsymPath (settings , destination)
143
+
144
+ buildNumber = settings[:buildNumber]
145
+ applicationName = settings[:applicationName]
146
+
147
+ remotePath = destination["path"]
148
+ dsymName = "#{applicationName}.#{buildNumber}.app.dSYM.zip"
149
+
150
+ "#{remotePath}/#{dsymName}"
151
+
152
+ end
153
+
154
+ #
155
+ # Extra
156
+ #
157
+
158
+
159
+ def remoteDTMobFile
160
+
161
+ "./dtmob.xml"
162
+
163
+ end
164
+
165
+ def localDTMobFile
166
+
167
+ "/tmp/dtmob.xml"
168
+
169
+ end
170
+
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'plist'
5
+ require 'parse-ruby-client'
6
+
7
+ require_relative 'paths.rb'
8
+
9
+
10
+ def generatePlist (settings)
11
+
12
+ puts "Creation du plist"
13
+
14
+ buildConfiguration = settings[:buildConfiguration]
15
+ buildDirectory = settings[:buildDirectory]
16
+ buildNumber = settings[:buildNumber]
17
+ projectInfosPath = settings[:projectInfosPath]
18
+
19
+ projectInfos = Plist::parse_xml(projectInfosPath)
20
+ deployPlistPath = deployPlistPath(settings)
21
+
22
+ deployPlist = Hash.new
23
+ items = Array.new
24
+ item = Hash.new
25
+
26
+
27
+ assets = Array.new
28
+ asset = Hash.new
29
+ asset['kind'] = 'software-package'
30
+
31
+ asset['url'] = settings[:deploy]["uploadServer"]["ipa"][0]["publicURL"] + "/" + ipaName(settings)
32
+
33
+ assets.push asset
34
+
35
+ metadata = Hash.new
36
+ metadata['bundle-identifier'] = settings[:deploy]["infosPlist"]["CFBundleIdentifier"]
37
+ metadata['bundle-version'] = projectInfos['CFBundleVersion']
38
+ metadata['subtitle'] = 'by SoLocal'
39
+ metadata['title'] = settings[:deploy]["infosPlist"]["CFBundleDisplayName"]
40
+ metadata['kind'] = 'software'
41
+
42
+ item['assets'] = assets
43
+ item['metadata'] = metadata
44
+
45
+ items.push item
46
+ deployPlist['items'] = items
47
+ Plist::Emit.save_plist(deployPlist , deployPlistPath)
48
+
49
+ end
50
+
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+
5
+ def load_settings(deploy)
6
+
7
+ settings = Hash.new
8
+
9
+ settings[:deploy] = deploy
10
+
11
+ settings[:applicationName] = deploy["infosPlist"]["CFBundleDisplayName"]
12
+ settings[:CFBundleVersion] = deploy["infosPlist"]["CFBundleVersion"]
13
+
14
+ settings[:projectDirectory] = Dir.pwd
15
+ settings[:projectInfosPath] = settings[:projectDirectory] + "/" + deploy["paths"]["infosPlistRelativePath"]
16
+
17
+ settings[:bundleName] = deploy["build"]["projectName"]
18
+ settings[:workspaceName] = deploy["build"]["workspaceName"]
19
+ settings[:schemeName] = deploy["build"]["schemeName"]
20
+ settings[:targetSDK] = deploy["build"]["targetSDK"]
21
+
22
+ settings[:buildConfiguration] = deploy["build"]["buildConfiguration"]
23
+ settings[:buildDirectory] = settings[:projectDirectory] + "/" + deploy["paths"]["buildRelativePath"]
24
+ settings[:buildNumber] = `git rev-list --max-count=1 HEAD`[0..7]
25
+
26
+ settings[:gitSHA1] = `git rev-list --max-count=1 HEAD`[0..7]
27
+
28
+ settings[:signingIdentity] = deploy["signing"]["identity"]
29
+ settings[:provisioningProfile] = "\"#{settings[:projectDirectory]}/#{deploy["signing"]["profile"]}\""
30
+
31
+ settings
32
+
33
+ end
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'plist'
4
+
5
+ require_relative 'paths.rb'
6
+
7
+ # adapt this shell script in ruby
8
+ # http://www.merowing.info/2013/03/overlaying-application-version-on-top-of-your-icon/
9
+
10
+
11
+ def updateIcon (settings)
12
+
13
+ iconsBasePath = "#{settings[:projectDirectory]}/PagesJaunes/Data/Images/SPLASH+ICONE"
14
+ icons = [["icone_base.png" , "icone.png"] , ["icone_base@2x.png" , "icone@2x.png"]]
15
+
16
+ should_update_icon = settings[:deploy]["icon"]["addExtraInfosInIcon"]
17
+
18
+ # if !should_update_icon
19
+ # return
20
+ # end
21
+
22
+ basePath = appPath(settings)
23
+
24
+ icons.each do |files|
25
+
26
+ source_file = "#{iconsBasePath}/#{files[0]}"
27
+ dest_file = "#{basePath}/#{files[1]}"
28
+
29
+ puts "Modification de #{source_file}"
30
+ puts "vers #{dest_file}"
31
+
32
+ addInfosToIcon settings , source_file , dest_file
33
+
34
+ end
35
+
36
+ end
37
+
38
+ def addInfosToIcon (settings , source_file , dest_file)
39
+
40
+ projectInfosPath = settings[:projectInfosPath]
41
+ projectInfos = Plist::parse_xml(projectInfosPath)
42
+
43
+ version = projectInfos["CFBundleVersion"]
44
+ commit = `git rev-parse --short HEAD`.strip
45
+ branch = `git rev-parse --abbrev-ref HEAD`.strip
46
+
47
+ width = `identify -format %w #{source_file}`
48
+
49
+ caption = iconCaptionForDeploy settings[:deploy]
50
+
51
+ command = "convert -background '#0008'"
52
+ command += " -fill white -gravity center"
53
+ command += " -size #{width}x40"
54
+ command += " caption:\"#{caption}\" \"#{source_file}\""
55
+ command += " +swap -gravity south -composite \"#{dest_file}\""
56
+
57
+ system(command)
58
+
59
+ end
60
+
61
+ def iconCaptionForDeploy(deploy)
62
+
63
+ caption = ""
64
+
65
+ if !deploy["icon"]["addBuildNumber"]
66
+ caption += "#{version}"
67
+ end
68
+
69
+
70
+ if !deploy["icon"]["addCommitId"]
71
+ caption += "#{commit}"
72
+ end
73
+
74
+ caption
75
+ end
@@ -0,0 +1,210 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'net/scp'
5
+ require 'net/ftp'
6
+ require 'net/ssh'
7
+
8
+ require 'nokogiri'
9
+ require 'date'
10
+
11
+ require_relative 'paths.rb'
12
+
13
+ def uploadArtefacts(settings)
14
+
15
+ uploadPlist(settings)
16
+ uploadIPA(settings)
17
+
18
+ # legacy, shouldn't be needed when the old DTAppStore will no more be used.
19
+ updateDTMobXML settings
20
+
21
+ end
22
+
23
+ def uploadFiles(settings , destination , files_to_upload)
24
+
25
+ host = destination["host"]
26
+ login = destination["login"]
27
+ path = destination["path"]
28
+
29
+ if (destination["protocol"] == "ssh")
30
+ uploadViaSSH(host , login , path, files_to_upload)
31
+
32
+ elsif (destination["protocol"] == "ftp")
33
+ password = destination["password"]
34
+ uploadViaFTP(host , login , password, path, files_to_upload)
35
+
36
+ else
37
+ puts "Protocole de téléversement inconnu"
38
+
39
+ end
40
+
41
+ end
42
+
43
+ def uploadIPA(settings)
44
+
45
+ settings[:deploy]["uploadServer"]["ipa"].each do |destination|
46
+
47
+ ipaPath = ipaPath (settings)
48
+ remoteIpaPath = remoteIpaPath (settings , destination)
49
+
50
+ dsymPath = zippedDsymPath(settings)
51
+ remoteDsymPath = remoteDsymPath(settings , destination)
52
+
53
+ files_to_upload = [[ipaPath , remoteIpaPath] , [dsymPath , remoteDsymPath]]
54
+
55
+ uploadFiles(settings , destination , files_to_upload)
56
+
57
+ end
58
+
59
+ end
60
+
61
+ def uploadPlist(settings)
62
+
63
+ settings[:deploy]["uploadServer"]["plist"].each do |destination|
64
+
65
+ deployPlistPath = deployPlistPath (settings)
66
+ remoteDeployPlistPath = remoteDeployPlistPath (settings , destination)
67
+
68
+ files_to_upload = [[deployPlistPath , remoteDeployPlistPath]]
69
+
70
+ uploadFiles(settings , destination , files_to_upload)
71
+
72
+ end
73
+
74
+ end
75
+
76
+ # files_to_upload is an array of arrays
77
+ # that must be like [local_file_path , remote_file_path]
78
+ def uploadViaSSH(host , login , path, files_to_upload)
79
+
80
+ # on vérifie si le dossier existe
81
+ check_command = "if [ ! -d \"#{path}\" ]; then mkdir \"#{path}\"; fi"
82
+
83
+ Net::SSH.start(host, login) do |ssh|
84
+ # capture all stderr and stdout output from a remote process
85
+ output = ssh.exec!(check_command)
86
+
87
+ puts "check: #{check_command}"
88
+ puts "output : #{output}"
89
+ end
90
+
91
+ Net::SCP.start(host, login) do |scp|
92
+ files_to_upload.each do |names|
93
+ puts 'Envoi du fichier ' + names[0] + ' vers ' + names[1]
94
+ scp.upload!(names[0].to_s, names[1])
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ def checkPathOnFTP(host, usermame , password , path)
101
+
102
+ folders = path.split("/")
103
+
104
+ ftp = Net::FTP.new(host)
105
+ ftp.login(usermame , password)
106
+
107
+ createFolders(ftp , folders)
108
+
109
+ ftp.close
110
+
111
+ end
112
+
113
+ def createFolders(ftp_connection , folders)
114
+
115
+ if folders.length < 2
116
+ return
117
+ end
118
+
119
+ ftp_connection.chdir(folders[0])
120
+ liste = ftp_connection.list
121
+
122
+ if ! (liste.any? { |element| element.include? folders[1]} )
123
+ ftp_connection.mkdir(folders[1])
124
+ end
125
+
126
+ createFolders(ftp_connection , folders.slice(1 , folders.length - 1))
127
+
128
+ end
129
+
130
+
131
+ # files_to_upload is an array of arrays
132
+ # that must be like [local_file_path , remote_file_path]
133
+ def uploadViaFTP(host, usermame , password , path, files_to_upload)
134
+
135
+ checkPathOnFTP(host, usermame , password , path)
136
+
137
+ # on est sûr d'avoir le dossier qu'il faut
138
+ # on fait la vraie connexion
139
+
140
+ ftp = Net::FTP.new(host)
141
+
142
+ ftp.login(usermame , password)
143
+
144
+ # ftp.chdir(path)
145
+
146
+ files_to_upload.each do |names|
147
+ puts "host: #{host}"
148
+ puts 'Envoi du fichier ' + names[0] + ' vers ' + names[1]
149
+ ftp.putbinaryfile(names[0].to_s, names[1])
150
+ end
151
+
152
+ ftp.close
153
+
154
+ end
155
+
156
+
157
+ def updateDTMobXML (settings)
158
+
159
+ # après upload des artefacts, on peut mettre à jour le fichier dtmob.xml
160
+ # et pourquoi pas dsem.xml
161
+
162
+ puts "Pas de mise à jour du dtmob.xml pour le moment"
163
+
164
+ return
165
+
166
+ host = settings[:deploy]["uploadServer"]["ipa"][0]["host"]
167
+ login = settings[:deploy]["uploadServer"]["ipa"][0]["login"]
168
+ path = settings[:deploy]["uploadServer"]["ipa"][0]["path"]
169
+ buildNumber = settings[:buildNumber]
170
+
171
+ dtmobApplicationName = settings[:deploy]["uploadServer"]["ipa"][0]["applicationTitle"]
172
+ dtmobApplicationVersion = settings[:deploy]["uploadServer"]["ipa"][0]["applicationVersion"]
173
+
174
+ Net::SCP.start(host, login) do |scp|
175
+ puts 'Mise-à-jour du fichier dtmob.xml'
176
+ scp.download!(remoteDTMobFile, localDTMobFile)
177
+
178
+ file = File.read(localDTMobFile)
179
+ dtmob = Nokogiri::XML(file)
180
+
181
+ timeFormat = "%Y-%m-%d %H-%M-%S"
182
+ lastUpdate = DateTime.now.strftime(timeFormat)
183
+ applicationXPath = "//application[title='#{dtmobApplicationName}']"
184
+ versionXPath = "version[numero='#{dtmobApplicationVersion}']"
185
+ changeLogXPath = "changelog"
186
+ changeLogContent = <<-EOXML
187
+ <![CDATA[
188
+ <ul>
189
+ <li>Last update: #{lastUpdate}</li>
190
+ <li>Build number: #{buildNumber}</li>
191
+ </ul>]]>
192
+ EOXML
193
+
194
+ application = dtmob.xpath(applicationXPath)
195
+ version = application.xpath(versionXPath)
196
+
197
+ changeLog = version.xpath(changeLogXPath).first
198
+ changeLog.inner_html = changeLogContent
199
+
200
+ # save the output into a new file
201
+ File.open(localDTMobFile, "w") do |f|
202
+ f.write dtmob.to_xml
203
+ end
204
+
205
+
206
+ scp.upload(localDTMobFile , remoteDTMobFile)
207
+ end
208
+
209
+ end
210
+
@@ -0,0 +1,3 @@
1
+ module Mercure
2
+ VERSION = "0.0.10"
3
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mercure/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mercure"
8
+ spec.version = Mercure::VERSION
9
+
10
+ spec.homepage = 'https://github.com/teriiehina/mercure'
11
+ spec.license = 'MIT'
12
+
13
+ spec.date = '2014-03-06'
14
+ spec.summary = "Build and distribute iOS app"
15
+ spec.description = "A tool that works only with plist files"
16
+ spec.authors = ["Peter Meuel"]
17
+ spec.email = 'peter@teriiehina.net'
18
+
19
+
20
+ spec.files = `git ls-files -z`.split("\x0")
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_runtime_dependency "bundler"
26
+ spec.add_runtime_dependency "rake"
27
+ spec.add_runtime_dependency 'thor'
28
+ spec.add_runtime_dependency 'plist'
29
+ spec.add_runtime_dependency 'net-scp'
30
+ spec.add_runtime_dependency 'parse-ruby-client'
31
+ spec.add_runtime_dependency 'nokogiri'
32
+ spec.add_runtime_dependency 'CFPropertyList'
33
+ spec.add_runtime_dependency 'xcpretty'
34
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mercure
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.10
5
+ platform: ruby
6
+ authors:
7
+ - Peter Meuel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: plist
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: net-scp
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: parse-ruby-client
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: nokogiri
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: CFPropertyList
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: xcpretty
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: A tool that works only with plist files
140
+ email: peter@teriiehina.net
141
+ executables:
142
+ - mercure
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - Gemfile
148
+ - LICENSE.txt
149
+ - README.md
150
+ - Rakefile
151
+ - bin/mercure
152
+ - lib/mercure.rb
153
+ - lib/mercure/build.rb
154
+ - lib/mercure/deploy.rb
155
+ - lib/mercure/git.rb
156
+ - lib/mercure/ipa.rb
157
+ - lib/mercure/parse.rb
158
+ - lib/mercure/paths.rb
159
+ - lib/mercure/plist.rb
160
+ - lib/mercure/settings.rb
161
+ - lib/mercure/update_icon.rb
162
+ - lib/mercure/upload.rb
163
+ - lib/mercure/version.rb
164
+ - mercure.gemspec
165
+ homepage: https://github.com/teriiehina/mercure
166
+ licenses:
167
+ - MIT
168
+ metadata: {}
169
+ post_install_message:
170
+ rdoc_options: []
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubyforge_project:
185
+ rubygems_version: 2.2.2
186
+ signing_key:
187
+ specification_version: 4
188
+ summary: Build and distribute iOS app
189
+ test_files: []