Skip to content

Commit

Permalink
fix(ios): Automate team id selection (#39)
Browse files Browse the repository at this point in the history
* [ios] Automate team id selection, prompt if more user has more than one team
* [ios] Save dev account password into CircleCI env variable (FASTLANE_PASSWORD) for CI access to dev account for deployments
* [circle] Create circle extension and move circle specific flows there
  • Loading branch information
plrdev authored May 9, 2019
1 parent b3a3962 commit 68c9816
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 76 deletions.
33 changes: 33 additions & 0 deletions src/extensions/circle-extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module.exports = toolbox => {
toolbox.circle = {
postEnvVariable: async ({
org,
project,
apiToken,
key,
value
}) => {
const { http } = toolbox
const api = http.create({
baseURL: 'https://circleci.com/api/v1.1/'
})

await api.post(
`project/github/${org}/${project}/envvar?circle-token=${apiToken}`,
{name: key, value: value },
{headers: {'Content-Type': 'application/json'}}
)
},
followProject: async ({ org, project, apiToken}) => {
const { http } = toolbox
const api = http.create({
baseURL: 'https://circleci.com/api/v1.1/'
})

const { status } = await api.post(
`project/github/${org}/${project}/follow?circle-token=${apiToken}`
)
return status
}
}
}
86 changes: 81 additions & 5 deletions src/extensions/ios-extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ module.exports = toolbox => {
resolve()
})
},
addBuildConfigurations: async (teamId) => {
addBuildConfigurations: async teamId => {
const { print, system, meta } = toolbox
return new Promise((resolve, reject) => {
system.run(`ruby ${meta.src}/ios.rb make_new_build_configurations ${teamId}`)
system.run(
`ruby ${meta.src}/ios.rb make_new_build_configurations ${teamId}`
)
resolve()
})
},
Expand All @@ -34,19 +36,93 @@ module.exports = toolbox => {
resolve()
})
},
produceApp: async ({ appId, devId, appName, developerTeamId, iTunesTeamId}) => {
produceApp: async ({
appId,
devId,
developerPassword,
appName,
developerTeamId,
iTunesTeamId
}) => {
const { print, system } = toolbox
return new Promise((resolve, reject) => {
const output = system.run(`fastlane produce -u ${devId} -a ${appId} --app_name "${appName}" --team_id "${developerTeamId}" --itc_team_id "${iTunesTeamId}"`)
const output = system.run(
`fastlane produce -u ${devId} -a ${appId} --app_name "${appName}" --team_id "${developerTeamId}" --itc_team_id "${iTunesTeamId}"`
)
resolve(output)
})
},
matchSync: async ({ certType, password }) => {
const { print, system } = toolbox
return new Promise((resolve, reject) => {
const output = system.run(`cd ios && (export MATCH_PASSWORD=${password}; bundle exec fastlane match ${certType})`)
const output = system.run(
`cd ios && (export MATCH_PASSWORD=${password}; bundle exec fastlane match ${certType})`
)
resolve(output)
})
},
getTeamIds: async accountInfo => {
const { print, system, meta } = toolbox
return new Promise(async (resolve, reject) => {
try {
const devTeams = await parseTeam('dev', accountInfo, meta.src)
const itcTeams = await parseTeam('itc', accountInfo, meta.src)
const teams = {
itcTeams: itcTeams,
devTeams: devTeams
}
resolve(teams)
} catch (e) {
reject(e)
}
})
}
}
}

const parseTeam = async (
teamType,
{ developerAccount, developerPassword },
path
) => {
return new Promise((resolve, reject) => {
const spawn = require('child_process').spawn
const child = spawn('ruby', [
`${path}/ios.rb`,
'get_team_id',
teamType,
developerAccount,
developerPassword
])
child.stdout.on('data', data => {
const dataStr = data.toString()
const regexpTeamLine = new RegExp(/^\d+[)]/)
const regexpTeamName = new RegExp(/"(.*?)"/)
const lines = dataStr.split('\n')
const teams = []
//if only one team found
if (lines.length === 2 && lines[1].length === 0) {
teams.push(lines[0])
resolve(teams)
}
//parse multiple teams
const regexpTeamId =
teamType === 'dev' ? new RegExp(/\)(.*?)"/) : new RegExp(/\((.*?)\)/)
lines.forEach(line => {
if (regexpTeamLine.test(line)) {
const teamName = regexpTeamName.exec(line)[1]
const teamId = regexpTeamId.exec(line)[1].trim()
teams.push({ name: teamName, id: teamId })
}
})
if (teams.length === 0) {
reject('Not able to retrieve teams, check account credentials')
}
resolve(teams)
})
child.stderr.on('data', data => {
reject('Not able to retrieve teams, check account credentials')
})
child.stdin.write('2\n')
})
}
2 changes: 0 additions & 2 deletions src/extensions/npm-extension.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// add your CLI-specific functionality here, which will then be accessible
// to your commands
const install = require('install-packages')

module.exports = toolbox => {
Expand Down
40 changes: 21 additions & 19 deletions src/flows/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const askQuestion = async (prompt, defaults = {}) => {
return prompt.ask(askGooglePlayJSONPath)
}

const initAndroid = async ({ android, http, prompt, print }, { project, org, apiToken, defaults }) => {
const initAndroid = async ({ android, http, prompt, print, circle }, { project, org, apiToken, defaults }) => {

const { jsonPath } = await askQuestion(prompt, defaults)

Expand All @@ -26,31 +26,33 @@ const initAndroid = async ({ android, http, prompt, print }, { project, org, ap
})

print.info('Store keystore to secret variables')
const api = http.create({
baseURL: 'https://circleci.com/api/v1.1/'
circle.postEnvVariable({
org,
project,
apiToken,
key: 'KEYSTORE',
value: keystoreFiles.encodedKeystore
})

await api.post(
`project/github/${org}/${project}/envvar?circle-token=${apiToken}`,
{name: 'KEYSTORE', value: keystoreFiles.encodedKeystore},
{headers: {'Content-Type': 'application/json'}}
)

print.info('Store keystore properties to secret variables')
await api.post(
`project/github/${org}/${project}/envvar?circle-token=${apiToken}`,
{name: 'KEYSTORE_PROPERTIES', value: keystoreFiles.keystoreProperties},
{headers: {'Content-Type': 'application/json'}}
)
circle.postEnvVariable({
org,
project,
apiToken,
key: 'KEYSTORE_PROPERTIES',
value: keystoreFiles.keystoreProperties
})

if (jsonPath !== '' && jsonPath !== undefined) {
print.info('Store Google Play JSON to secret variables')
const encodedPlayStoreJSON = android.base64EncodeJson(jsonPath)
await api.post(
`project/github/${org}/${project}/envvar?circle-token=${apiToken}`,
{name: 'GOOGLE_PLAY_JSON', value: encodedPlayStoreJSON},
{headers: {'Content-Type': 'application/json'}}
)
circle.postEnvVariable({
org,
project,
apiToken,
key: 'GOOGLE_PLAY_JSON',
value: encodedPlayStoreJSON
})
}
}

Expand Down
Loading

0 comments on commit 68c9816

Please sign in to comment.