Fix xcode9 provision, provide --quiet by default, enable -allowProvisioningUpdates - #3070
Conversation
…iet flags to xcodebuild and gradle, provide -allowProvisioningUpdates to xcodebuild > 9.0
…re mutually exclusive, teamId now should work with name if a provision that has the team id for the provided team name is found
ffb0e8e to
88f8629
Compare
- Make tests passing with NativeScript/nativescript-cli#3070 - Enable —provision tests for Xcode9
| const gradlew = this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew"; | ||
|
|
||
| const localArgs = [...gradleArgs]; | ||
| if (this.$logger.getLevel() === "INFO") { |
There was a problem hiding this comment.
You can use $loggingLevels.info here instead of a string
There was a problem hiding this comment.
let's keep it this way, $loggingLevels has a different purpose. I'll handle the logging levels in a separate PR and will change this code with a constant in it.
| return { devices, match }; | ||
| } | ||
|
|
||
| public async getDevelopmentTeams(): Promise<{ id: string, name: string }[]> { |
There was a problem hiding this comment.
{ id: string, name: string } could be extracted in an interface.
This is a personal preference though as I find named interfaces improve code readability
There was a problem hiding this comment.
This is used once, if I have to write it out in 2-3 places perhaps I will make it a separate interface. For now type inference works so well, this type is never written out anywhere else in the code.
There was a problem hiding this comment.
We have a scenario where we'll need interface, but let's discuss it personally and handle it in a separate PR once it is needed.
| } | ||
|
|
||
| public async getDevelopmentTeams(): Promise<{ id: string, name: string }[]> { | ||
| const teams: { [teamName: string]: Set<string> } = {}; |
There was a problem hiding this comment.
Same remark about the interface
There was a problem hiding this comment.
This is used locally and just once. I don't want to pollute the module with interfaces. It could be IDictionary<Set<string>> but then it would be even harder to figure out what the key would be.
| if (teamId === true) { | ||
| await this.$iOSProvisionService.listTeams(); | ||
| this.$errors.failWithoutHelp("Please provide team id or team name with the --teamId options."); | ||
| return false; |
There was a problem hiding this comment.
There's no need for this return statement - this.$errors.failWithoutHelp will terminate the process
There was a problem hiding this comment.
Omg. It returns void. :D I will make it "never".
There was a problem hiding this comment.
failWithoutHelp(message: string, ...args: any[]): never;
please use the never type for each method that terminate unconditionally the process or throw.
There was a problem hiding this comment.
I made a PR for 'never' but it is completely unrelated (I think) with this current PR:
telerik/mobile-cli-lib#1006
There was a problem hiding this comment.
Nice one! Yes, it is unrelated
| args.push(`CODE_SIGN_IDENTITY=${buildConfig.codeSignIdentity}`); | ||
| } | ||
| // These are now set in the .pbxproj, avoid passing them as arguments! | ||
| // if (buildConfig && buildConfig.codeSignIdentity) { |
There was a problem hiding this comment.
Do we want to keep this code commented out for future reference?
There was a problem hiding this comment.
I vote for deleting it
|
|
||
| if (provision !== undefined) { | ||
| if (signing && signing.style === "Manual") { | ||
| for (let name in signing.configurations) { |
There was a problem hiding this comment.
let name could be const name
There was a problem hiding this comment.
Can we have a lint rule for these?
There was a problem hiding this comment.
We can, but enabling it leads to 1400 compile errors, so I advise against this in this PR
| if (provision !== undefined) { | ||
| if (signing && signing.style === "Manual") { | ||
| for (let name in signing.configurations) { | ||
| let config = signing.configurations[name]; |
| <string>${options.teamID}</string> | ||
| `; | ||
| } | ||
| if (options && options.provision) { |
There was a problem hiding this comment.
A separate service/helper function could be extracted for getting the exportOptions.plist file and be reused here and here.
This could be done in another PR though
There was a problem hiding this comment.
The time is tight, let's do this in a separate PR if we ever touch these two again.
| } | ||
|
|
||
| await this.createIpa(projectRoot, projectData, buildConfig); | ||
| private async setupSigningFromTeam(projectRoot: string, projectData: IProjectData, teamId?: string) { |
There was a problem hiding this comment.
Is the teamId argument really optional here - what will happen if it is not passed - shouldUpdateXcode would be set to true and then Automatic signing will be set without a team.
| let shouldUpdateXcode = false; | ||
| if (signing && signing.style === "Automatic") { | ||
| if (signing.team !== teamId) { | ||
| // Maybe the provided team is name such as "Telerik AD" and we need to convert it to CH******37 |
There was a problem hiding this comment.
What if the team is passed as an id instead of a name - we'd still try and look for it as if it was a name
There was a problem hiding this comment.
Yes. I think it is highly unlikely to have a team name matching the randomly generated team ids on the same machine. teamId probably should be just team like the provision switch is not provisionIdentifier or provisionUUID. Being able to pass "Telerik AD" for team however is really convenient.
There was a problem hiding this comment.
My bad, I didn't manage to express my concern correctly - according to the docs you've written for --team-id one can either pass a team name or a team id.
So what of the case where the user knows the team id and passes it as a value to --team-id - we'd still look for it and validate it as if it was a team name
There was a problem hiding this comment.
The code here will do the following:
It will check if the arg passed to team-id matches the team in the Automatic signing style in Xcode. If it does, the native project and prepare are up-to-date.
If it does not - it will consider the team-id to be actually a team name, it will check for a team with name matching the provided team-id and if it finds one it will check if Xcode is configured to sign with that team's id.
This can fail if you have a team that has team id matching one of your other team's names, that's highly unlikely. If this raises as an issue we can split a team-id and team-name switches.
There was a problem hiding this comment.
I pretty much try to treat team-id as id, and eventually check the provisioning profiles if it were team name and map the name to id.
| const gradlew = this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew"; | ||
|
|
||
| const localArgs = [...gradleArgs]; | ||
| if (this.$logger.getLevel() === "INFO") { |
There was a problem hiding this comment.
let's keep it this way, $loggingLevels has a different purpose. I'll handle the logging levels in a separate PR and will change this code with a constant in it.
| const localArgs = [...gradleArgs]; | ||
| if (this.$logger.getLevel() === "INFO") { | ||
| localArgs.push("--quiet"); | ||
| this.$logger.info(`${gradlew} ${localArgs.join(" ")}`); |
There was a problem hiding this comment.
why do we want to print the command that we execute in the info level?
There was a problem hiding this comment.
Otherwise nothing is printed. I wanted to print something that indicates that a native build had started. I am ok to go for just "Xcode build..." and "Gradle build...", should I change these?
There was a problem hiding this comment.
I prefer using Gradle build...
In case you want to print dots, you can use:
const action = () => this.spawn(gradlew, localArgs, childProcessOpts, spawnFromEventOptions);
this.$logger.printInfoMessageOnSameLine("Gradle build...");
await this.$progressIndicator.showProgressIndicator(action(), 2000);There was a problem hiding this comment.
Doesn't this throw garbage progress indicator symbols around if the xcodebuild or gradle build actually output stuff? I've seen rogue npm progress bars printed at random.
There was a problem hiding this comment.
This actually sounds reasonable I'll give it a try.
There was a problem hiding this comment.
Ok we've agreed to use "Gradle build..." and "Xcode build...".
Bear in mind that we do 3 xcodebuild executions on clean "tns run ios" on device.
| <string>${exportOptionsMethod}</string>`; | ||
| if (options && options.provision) { | ||
| plistTemplate += ` <key>provisioningProfiles</key> | ||
| <dict> |
There was a problem hiding this comment.
this plist seems duplicate of the one used on line 234, can we have it on a single place and reuse it
There was a problem hiding this comment.
First Write, Second Copy, Third Refactor
There was a problem hiding this comment.
Agreed to handle this in a separate PR
| args.push(`CODE_SIGN_IDENTITY=${buildConfig.codeSignIdentity}`); | ||
| } | ||
| // These are now set in the .pbxproj, avoid passing them as arguments! | ||
| // if (buildConfig && buildConfig.codeSignIdentity) { |
There was a problem hiding this comment.
I vote for deleting it
| localArgs.push("-allowProvisioningUpdates"); | ||
| } | ||
| } catch (e) { | ||
| console.warn("Failed to use xcodebuild with -allowProvisioningUpdates due to error: " + e); |
There was a problem hiding this comment.
this should be $logger.warn
| } catch (e) { | ||
| console.warn("Failed to use xcodebuild with -allowProvisioningUpdates due to error: " + e); | ||
| } | ||
| if (this.$logger.getLevel() === "INFO") { |
There was a problem hiding this comment.
Same as above:
let's keep it this way, $loggingLevels has a different purpose. I'll handle the logging levels in a separate PR and will change this code with a constant in it.
| } | ||
| if (this.$logger.getLevel() === "INFO") { | ||
| localArgs.push("-quiet"); | ||
| this.$logger.info(`xcodebuild ${localArgs.join(" ")}`); |
There was a problem hiding this comment.
and again, is it important for the user to see the command we are executing. Until now this was not shown, can we show it in trace level only?
There was a problem hiding this comment.
Same,
xcodebuild will not output a single line if run with -quiet and no errors or warning were present. So far the user had seen 10 screens of output in place of this with all the flags and environment variables passed to Xcode, various subtools that compile storyboards or copy PNGs. All of it is now collapsed to this line. I think this line is important otherwise the CLI will stall for several seconds and the user won't know that the native build actually started.
Again I can change the message if you provide me a better one, but I think it is important to appear in the default logging mode when -quiet is passed.
There was a problem hiding this comment.
As above
In case you want to print dots, you can use:
const action = () => this.$childProcess.spawnFromEvent("xcodebuild", ... );
this.$logger.printInfoMessageOnSameLine("Building application...");
await this.$progressIndicator.showProgressIndicator(action(), 2000);| * Formats the argument so it can easily be copied from the terminal and provided as value for an option. | ||
| * @param arg The string to format. | ||
| */ | ||
| function cmdEscape(arg: string): string { |
There was a problem hiding this comment.
Maybe quoteString can do the same work for you?
There was a problem hiding this comment.
No. It does cmdEscape. Its purpose is to make the string passable as argument to an option. Telerik A D can be escaped as "Telerik A D" or it could be as Telerik\ A\ D and have no commas at all and I wouldn't care less which one would be the result of the escape. On the other hand the escaping is flawed, it would fail on Telerik "AD" as the commas will go nuts with "Telerik "AD"" :( but I don't have time to figure out better escaping.
There was a problem hiding this comment.
omg :D I clicked the link, you have cmdQuote :D I will use that one :)
commented
Aug 23, 2017
|
@rosen-vladimirov @Mitko-Kerezov |
Depends on:
#3069
This PR will:
(THIS ONE IS MY FAVOURITE!!!)
(we should improve that by somehow looking in the accounts registered in Xcode)