Full Code of jenkinsci/xcode-plugin for AI

master 831b1cdc61ba cached
250 files
784.6 KB
221.2k tokens
591 symbols
1 requests
Download .txt
Showing preview only (877K chars total). Download the full file or copy to clipboard to get everything.
Repository: jenkinsci/xcode-plugin
Branch: master
Commit: 831b1cdc61ba
Files: 250
Total size: 784.6 KB

Directory structure:
gitextract_872818gr/

├── .github/
│   ├── dependabot.yml
│   ├── release-drafter.yml
│   └── workflows/
│       └── cd.yaml
├── .gitignore
├── .mvn/
│   ├── extensions.xml
│   └── maven.config
├── CHANGELOG.md
├── Jenkinsfile
├── README.md
├── docs/
│   └── images/
│       └── e75543fce396e66c1ad66700d6e74156c2b730db.logo
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   ├── au/
    │   │   │   └── com/
    │   │   │       └── rayh/
    │   │   │           ├── BuildConfiguration.java
    │   │   │           ├── DSymFileFilter.java
    │   │   │           ├── DeveloperProfile.java
    │   │   │           ├── DeveloperProfileLoader.java
    │   │   │           ├── ExportIpa.java
    │   │   │           ├── GlobalConfigurationImpl.java
    │   │   │           ├── InfoPlist.java
    │   │   │           ├── JenkinsXCodeBuildOutputParser.java
    │   │   │           ├── Keychain.java
    │   │   │           ├── KeychainPasswordAndPath.java
    │   │   │           ├── KeychainPasswordAndPathBinding.java
    │   │   │           ├── KeychainPasswordAndPathImpl.java
    │   │   │           ├── KeychainUnlockStep.java
    │   │   │           ├── MobileProvisionParser.java
    │   │   │           ├── ProjectScheme.java
    │   │   │           ├── ProjectTarget.java
    │   │   │           ├── ProvisioningProfile.java
    │   │   │           ├── Team.java
    │   │   │           ├── XCArchiveFileFilter.java
    │   │   │           ├── XCodeAction.java
    │   │   │           ├── XCodeBuildNumberTokenMacro.java
    │   │   │           ├── XCodeBuildOutputParser.java
    │   │   │           ├── XCodeBuilder.java
    │   │   │           ├── XcodeBuildHelpParser.java
    │   │   │           ├── XcodeBuildListParser.java
    │   │   │           ├── XcodeCredentialsHelper.java
    │   │   │           ├── XcodeDeclarativeCredentialsHandler.java
    │   │   │           ├── XcodeProject.java
    │   │   │           ├── XcodeProjectFileFilter.java
    │   │   │           ├── XcodeProjectParser.java
    │   │   │           ├── XcodeSchemeFileFilter.java
    │   │   │           ├── XcodeTestSummariesParser.java
    │   │   │           └── report/
    │   │   │               ├── TestCase.java
    │   │   │               ├── TestError.java
    │   │   │               ├── TestFailure.java
    │   │   │               └── TestSuite.java
    │   │   └── hudson/
    │   │       └── plugins/
    │   │           └── xcode/
    │   │               └── XcodeInstallation.java
    │   ├── resources/
    │   │   ├── au/
    │   │   │   └── com/
    │   │   │       └── rayh/
    │   │   │           ├── DeveloperProfile/
    │   │   │           │   ├── config.groovy
    │   │   │           │   ├── config_ja.properties
    │   │   │           │   ├── help-description.html
    │   │   │           │   ├── help-description_ja.html
    │   │   │           │   ├── help-password.html
    │   │   │           │   ├── help-password_ja.html
    │   │   │           │   ├── help.html
    │   │   │           │   ├── help_ja.html
    │   │   │           │   └── upload.groovy
    │   │   │           ├── DeveloperProfileLoader/
    │   │   │           │   ├── config.jelly
    │   │   │           │   └── config_ja.properties
    │   │   │           ├── ExportIpa/
    │   │   │           │   ├── config.jelly
    │   │   │           │   ├── config_ja.properties
    │   │   │           │   ├── help-archiveDir.html
    │   │   │           │   └── help-archiveDir_ja.html
    │   │   │           ├── GlobalConfigurationImpl/
    │   │   │           │   ├── config.jelly
    │   │   │           │   └── config_ja.properties
    │   │   │           ├── KeychainPasswordAndPathBinding/
    │   │   │           │   ├── config-variables.jelly
    │   │   │           │   ├── config-variables_ja.properties
    │   │   │           │   ├── help-inSearchPathVariable.html
    │   │   │           │   ├── help-inSearchPathVariable_ja.html
    │   │   │           │   ├── help-keychainPathVariable.html
    │   │   │           │   ├── help-keychainPathVariable_ja.html
    │   │   │           │   ├── help-passwordVariable.html
    │   │   │           │   └── help-passwordVariable_ja.html
    │   │   │           ├── KeychainPasswordAndPathImpl/
    │   │   │           │   ├── credentials.jelly
    │   │   │           │   ├── credentials_ja.properties
    │   │   │           │   ├── help-description.html
    │   │   │           │   ├── help-description_ja.html
    │   │   │           │   ├── help-id.html
    │   │   │           │   ├── help-id_ja.html
    │   │   │           │   ├── help-keychainPath.html
    │   │   │           │   ├── help-keychainPath_ja.html
    │   │   │           │   ├── help-password.html
    │   │   │           │   └── help-password_ja.html
    │   │   │           ├── KeychainUnlockStep/
    │   │   │           │   ├── config.jelly
    │   │   │           │   └── config_ja.properties
    │   │   │           ├── Messages.properties
    │   │   │           ├── Messages_ja.properties
    │   │   │           └── XCodeBuilder/
    │   │   │               ├── config.jelly
    │   │   │               ├── config_ja.properties
    │   │   │               ├── help-allowFailingBuildResults.html
    │   │   │               ├── help-allowFailingBuildResults_ja.html
    │   │   │               ├── help-buildDir.html
    │   │   │               ├── help-buildDir_ja.html
    │   │   │               ├── help-buildIpa.html
    │   │   │               ├── help-buildIpa_ja.html
    │   │   │               ├── help-bundleID.html
    │   │   │               ├── help-bundleIDInfoPlistPath.html
    │   │   │               ├── help-bundleIDInfoPlistPath_ja.html
    │   │   │               ├── help-bundleID_ja.html
    │   │   │               ├── help-cfBundleShortVersionStringValue.html
    │   │   │               ├── help-cfBundleShortVersionStringValue_ja.html
    │   │   │               ├── help-cfBundleVersionValue.html
    │   │   │               ├── help-cfBundleVersionValue_ja.html
    │   │   │               ├── help-changeBundleID.html
    │   │   │               ├── help-changeBundleID_ja.html
    │   │   │               ├── help-cleanBeforeBuild.html
    │   │   │               ├── help-cleanBeforeBuild_ja.html
    │   │   │               ├── help-cleanResultBundlePath.html
    │   │   │               ├── help-cleanResultBundlePath_ja.html
    │   │   │               ├── help-codeSigningIdentity.html
    │   │   │               ├── help-codeSigningIdentity_ja.html
    │   │   │               ├── help-configuration.html
    │   │   │               ├── help-configuration_ja.html
    │   │   │               ├── help-embeddedProfileFile.html
    │   │   │               ├── help-embeddedProfileFile_ja.html
    │   │   │               ├── help-generateArchive.html
    │   │   │               ├── help-generateArchive_ja.html
    │   │   │               ├── help-globalDevelopmentTeam_ja.html
    │   │   │               ├── help-globalKeychainName_ja.html
    │   │   │               ├── help-interpretTargetAsRegEx.html
    │   │   │               ├── help-interpretTargetAsRegEx_ja.html
    │   │   │               ├── help-ipaName_ja.html
    │   │   │               ├── help-keychainName.html
    │   │   │               ├── help-keychainName_ja.html
    │   │   │               ├── help-keychainPath.html
    │   │   │               ├── help-keychainPath_ja.html
    │   │   │               ├── help-keychainPwd.html
    │   │   │               ├── help-keychainPwd_ja.html
    │   │   │               ├── help-logfileOutputDirectory.html
    │   │   │               ├── help-logfileOutputDirectory_ja.html
    │   │   │               ├── help-resultBundlePath.html
    │   │   │               ├── help-resultBundlePath_ja.html
    │   │   │               ├── help-sdk.html
    │   │   │               ├── help-sdk_ja.html
    │   │   │               ├── help-signIpaOnXcrun.html
    │   │   │               ├── help-signIpaOnXcrun_ja.html
    │   │   │               ├── help-symRoot.html
    │   │   │               ├── help-symRoot_ja.html
    │   │   │               ├── help-target.html
    │   │   │               ├── help-target_ja.html
    │   │   │               ├── help-unlockKeychain_ja.html
    │   │   │               ├── help-useLegacyBuildSystem.html
    │   │   │               ├── help-useLegacyBuildSystem_ja.html
    │   │   │               ├── help-xcodeProjectFile_ja.html
    │   │   │               ├── help-xcodeProjectPath_ja.html
    │   │   │               ├── help-xcodeSchema_ja.html
    │   │   │               ├── help-xcodeWorkspaceFile_ja.html
    │   │   │               ├── help-xcodebuildArguments.html
    │   │   │               └── help-xcodebuildArguments_ja.html
    │   │   ├── hudson/
    │   │   │   └── plugins/
    │   │   │       └── xcode/
    │   │   │           └── XcodeInstallation/
    │   │   │               ├── config.jelly
    │   │   │               ├── config_it.properties
    │   │   │               ├── config_ja.properties
    │   │   │               ├── help-home.html
    │   │   │               └── help-home_ja.html
    │   │   └── index.jelly
    │   └── webapp/
    │       ├── help/
    │       │   ├── help-appIDandProvisionUUID.html
    │       │   ├── help-appIDandProvisionUUID_ja.html
    │       │   ├── help-assetPackManifestURL.html
    │       │   ├── help-assetPackManifestURL_ja.html
    │       │   ├── help-automaticSigning.html
    │       │   ├── help-automaticSigning_ja.html
    │       │   ├── help-bundleID.html
    │       │   ├── help-bundleID_ja.html
    │       │   ├── help-compileBitcode.html
    │       │   ├── help-compileBitcode_ja.html
    │       │   ├── help-copyProvisioningProfile.html
    │       │   ├── help-copyProvisioningProfile_ja.html
    │       │   ├── help-credentialKeychainId.html
    │       │   ├── help-credentialKeychainId_ja.html
    │       │   ├── help-developmentTeamID.html
    │       │   ├── help-developmentTeamID_ja.html
    │       │   ├── help-displayImageURL.html
    │       │   ├── help-displayImageURL_ja.html
    │       │   ├── help-embedOnDemandResources.html
    │       │   ├── help-embedOnDemandResources_ja.html
    │       │   ├── help-fullSizeImageURL.html
    │       │   ├── help-fullSizeImageURL_ja.html
    │       │   ├── help-globalDevelopmentTeam.html
    │       │   ├── help-globalDevelopmentTeam_ja.html
    │       │   ├── help-globalKeychainName.html
    │       │   ├── help-globalKeychainName_ja.html
    │       │   ├── help-importDeveloperProfile.html
    │       │   ├── help-importDeveloperProfileId.html
    │       │   ├── help-importDeveloperProfileId_ja.html
    │       │   ├── help-importDeveloperProfile_ja.html
    │       │   ├── help-importIntoExistingKeychain.html
    │       │   ├── help-importIntoExistingKeychain_ja.html
    │       │   ├── help-importKeychainId.html
    │       │   ├── help-importKeychainId_ja.html
    │       │   ├── help-importKeychainName.html
    │       │   ├── help-importKeychainName_ja.html
    │       │   ├── help-ipaExportMethod.html
    │       │   ├── help-ipaExportMethod_ja.html
    │       │   ├── help-ipaManifestPlistUrl.html
    │       │   ├── help-ipaManifestPlistUrl_ja.html
    │       │   ├── help-ipaName.html
    │       │   ├── help-ipaName_ja.html
    │       │   ├── help-ipaOutputDirectory.html
    │       │   ├── help-ipaOutputDirectory_ja.html
    │       │   ├── help-manifestPlistURL.html
    │       │   ├── help-manifestPlistURL_ja.html
    │       │   ├── help-manualSigning.html
    │       │   ├── help-manualSigning_ja.html
    │       │   ├── help-onDemandResourcesURL.html
    │       │   ├── help-onDemandResourcesURL_ja.html
    │       │   ├── help-provisioningUUID.html
    │       │   ├── help-provisioningUUID_ja.html
    │       │   ├── help-readFromProject.html
    │       │   ├── help-readFromProject_ja.html
    │       │   ├── help-thinning.html
    │       │   ├── help-thinning_ja.html
    │       │   ├── help-unlockKeychain.html
    │       │   ├── help-unlockKeychain_ja.html
    │       │   ├── help-uploadBitcode.html
    │       │   ├── help-uploadBitcode_ja.html
    │       │   ├── help-uploadSymbols.html
    │       │   ├── help-uploadSymbols_ja.html
    │       │   ├── help-xcodeProjectFile.html
    │       │   ├── help-xcodeProjectFile_ja.html
    │       │   ├── help-xcodeProjectPath.html
    │       │   ├── help-xcodeProjectPath_ja.html
    │       │   ├── help-xcodeSchema.html
    │       │   ├── help-xcodeSchema_ja.html
    │       │   ├── help-xcodeToolsVersion.html
    │       │   ├── help-xcodeToolsVersion_ja.html
    │       │   ├── help-xcodeWorkspaceFile.html
    │       │   └── help-xcodeWorkspaceFile_ja.html
    │       ├── help-cleanTestReports.html
    │       └── help-xcodebuildArguments.html
    └── test/
        ├── java/
        │   ├── Pkcs12.java
        │   ├── Pkcs7.java
        │   └── au/
        │       └── com/
        │           └── rayh/
        │               ├── JenkinsXCodeBuildOutputParserTest.java
        │               ├── OutputParserTests.java
        │               ├── XCodeBuildHelpParserTest.java
        │               ├── XCodeBuildListParserTest.java
        │               ├── XCodeBuildOutputParserTest.java
        │               ├── XCodeBuilderTest.java
        │               ├── XcodeProjectParserTest.java
        │               └── XcodeTestSummariesParserTest.java
        └── resources/
            ├── XCTest_output_complex_1.txt
            ├── XCTest_output_complex_2.txt
            ├── XCTest_output_crashing_1.txt
            ├── XCTest_output_failing_1.txt
            ├── XCTest_output_failing_2.txt
            ├── XCTest_output_passing_1.txt
            ├── xcodebuildhelp-invalid.txt
            ├── xcodebuildhelp-valid.txt
            ├── xcodebuildlist-invalid1.txt
            ├── xcodebuildlist-invalid2.txt
            └── xcodebuildlist-valid.txt

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: maven
  directory: /
  schedule:
    interval: weekly
- package-ecosystem: github-actions
  directory: /
  schedule:
    interval: weekly


================================================
FILE: .github/release-drafter.yml
================================================
_extends: .github


================================================
FILE: .github/workflows/cd.yaml
================================================
# Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins

name: cd
on:
  workflow_dispatch:
  check_run:
    types:
      - completed

jobs:
  validate:
    runs-on: ubuntu-latest
    outputs:
      should_release: ${{ steps.verify-ci-status.outputs.result == 'success' && steps.interesting-categories.outputs.interesting == 'true' }}
    steps:
      - name: Verify CI status
        uses: jenkins-infra/verify-ci-status-action@v1.2.1
        id: verify-ci-status
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          output_result: true

      - name: Release Drafter
        uses: release-drafter/release-drafter@v5
        if: steps.verify-ci-status.outputs.result == 'success'
        with:
          name: next
          tag: next
          version: next
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Check interesting categories
        uses: jenkins-infra/interesting-category-action@v1.2.0
        id: interesting-categories
        if: steps.verify-ci-status.outputs.result == 'success'
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  release:
    runs-on: ubuntu-latest
    needs: [validate]
    if: needs.validate.outputs.should_release == 'true'
    steps:
    - name: Check out
      uses: actions/checkout@v3
      with:
        fetch-depth: 0

    - name: Set up JDK 8
      uses: actions/setup-java@v3
      with:
        distribution: temurin
        java-version: 8

    - name: Release
      uses: jenkins-infra/jenkins-maven-cd-action@v1.3.1
      with:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
        MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}


================================================
FILE: .gitignore
================================================
target
work
.idea
test-*
*.iml
.DS_Store
*.orig
/examples
TEST-*


================================================
FILE: .mvn/extensions.xml
================================================
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0 http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
  <extension>
    <groupId>io.jenkins.tools.incrementals</groupId>
    <artifactId>git-changelist-maven-extension</artifactId>
    <version>1.3</version>
  </extension>
</extensions>


================================================
FILE: .mvn/maven.config
================================================
-Pconsume-incrementals
-Pmight-produce-incrementals
-Dchangelist.format=%d.v%s


================================================
FILE: CHANGELOG.md
================================================
Changelog
===

### Newer versions

See [GitHub releases](https://github.com/jenkinsci/xcode-plugin/releases)

#### Version 2.0.14 (14th Nov 2019)
-   ##### Fix backward compatibility problem at Import Developer Profile.

#### Version 2.0.13 (14th Nov 2019)
-   ##### Information to access the macOS keychain has been moved to credentials.
-   Fixed a bug in the project parser when multiple projects are in the workspace. ([JENKINS-59523](https://issues.jenkins-ci.org/browse/JENKINS-59523), [JENKINS-59609](https://issues.jenkins-ci.org/browse/JENKINS-59609))

#### Version 2.0.12 (27th May 2019)

-   ##### Allow to unlock/lock keychain on demand. ([JENKINS-56909](https://issues.jenkins-ci.org/browse/JENKINS-56909))

-   Modified to encrypt the keychain password. ([PR
    \#102](https://github.com/jenkinsci/xcode-plugin/pull/102))
-   Fix display bug developer profile credentials and more. ([PR
    \#103](https://github.com/jenkinsci/xcode-plugin/pull/103))

#### Version 2.0.11 (19th Feb 2019)

-   ##### Added a function to obtain the status of the test from the outline of the test result 'TestSummaries.plist'.

#### Version 2.0.10 (19th Nov 2018)

-   ##### Fix broken Xcode Project Parser. ([JENKINS-54414](http://JENKINS-54414), [JENKINS-54113](https://issues.jenkins-ci.org/browse/JENKINS-54113))

#### Version 2.0.9 (2nd Nov 2018)

-   ##### Added a option to use the 'Legacy Build System' instead of 'New Builld System' which became available from Xcode 9.

#### Version 2.0.8 (10th Oct 2018)

-   Corresponds when there is no DEVELOPMENT\_TEAM entry in the old
    Xcode project.
-   Delete unnecessary error messages.
-   When copying the provisioning profile from the project location, it
    needs to be done before Xcode compilation, so it is fixed.
-   Fixed a bug that error message got mixed when parsing provisioning
    profile and analysis failed.

#### Version 2.0.7 (20th Sep 2018)

-   Added the ability to copy provisioning profile files to manual code
    signing.
-   Change the help for importing developer profile to more detailed
    one.
-   Enhance backward compatibility.
-   Added a function to retrieve information necessary for CodeSign from
    Xcode project.

#### Version 2.0.6 (16th Aug 2018)

-   Fixed a bug that key chain was not unlocked properly when importing
    developer profile to keychain.
-   Added input validation when setting up developer profile loader.
-   Added input validation when setting up export IPA.
-   Fix some bugs.

#### Version 2.0.5 (9th Aug 2018)

-   More compatibility for Pipeline.
-   Added function to import developer profile into existing keychain.
-   Added a function to set exportOptions.plist an option for deleting
    Swift symbols when exporting IPA.

#### Version 2.0.4 (22th Jun 2018)

-   I will display an error message if the developer profile is not
    loaded.

#### Version 2.0.3 (18th Jun 2018)

-   Implemented the ability to export IPA files from already compiled
    archives.
-   [JENKINS-50266](https://issues.jenkins-ci.org/browse/JENKINS-50266)
    : Fix custom xcodebuild arguments not passed through to export
    archive step.
-   [JENKINS-51418](https://issues.jenkins-ci.org/browse/JENKINS-51418)
    : Fix to always be able to use developer team ID as a parameter
    regardless of automatic code signature.
-   Fix the Plugin is abnormally terminate if the out of order of lines
    from Xcodebuild output is changed.
-   Added a function to retrieve necessary information for code
    signature from compiled archive.
-   Support multiple versions of Xcode without using 'EnvInject Plugin'.

#### Version 2.0.2 (30th Apr 2018)

-   We released again due to infrastructure related problems, but the
    contents are the same as Ver 2.0.1

#### Version 2.0.1 (26th Apr 2018)

-   Supports Xcode 9 ([PR
    \#86](https://github.com/jenkinsci/xcode-plugin/pull/86),
    [PR\#87](https://github.com/jenkinsci/xcode-plugin/pull/87), [JENKINS-47744](https://issues.jenkins-ci.org/browse/JENKINS-45509), [JENKINS-45509](https://issues.jenkins-ci.org/browse/JENKINS-45509))
-   Adding Pipeline support for importDeveloperProfile and adding
    symbols ([PR
    \#89](https://github.com/jenkinsci/xcode-plugin/pull/89))

#### Version 2.0.0 (24th May 2017)

-    The plugin now requires Java 7 and Jenkins core \>= 1.625.1

-    The plugin now requires Xcode \>= 7

-   New : Supports Xcode 7/8
    ([PR\#76](https://github.com/jenkinsci/xcode-plugin/pull/76),
    [PR\#78](https://github.com/jenkinsci/xcode-plugin/pull/78), [JENKINS-44203](https://issues.jenkins-ci.org/browse/JENKINS-44203){.issue-link}, [JENKINS-44151](https://issues.jenkins-ci.org/browse/JENKINS-44151){.issue-link}, [JENKINS-43226](https://issues.jenkins-ci.org/browse/JENKINS-43226){.issue-link}, [JENKINS-43163](https://issues.jenkins-ci.org/browse/JENKINS-43163){.issue-link}, [JENKINS-38799](https://issues.jenkins-ci.org/browse/JENKINS-38799){.issue-link}, [JENKINS-38777](https://issues.jenkins-ci.org/browse/JENKINS-38777){.issue-link},
    [JENKINS-34307](https://issues.jenkins-ci.org/browse/JENKINS-34307){.issue-link}) 
    -   Replace 'xcrun PackageApplication' by 'xcodebuild
        -exportArchive' to package ipa

    -   New Development Team parameter which can be configured globally
        in Jenkins Global settings or locally at the project level

-   New : Adds regex for parsing UI test failures (for Xcode 8)
    ([PR\#75](https://github.com/jenkinsci/xcode-plugin/pull/75), [JENKINS-40938](https://issues.jenkins-ci.org/browse/JENKINS-40938){.issue-link})

-   New : Adds support
    ([PR\#74](https://github.com/jenkinsci/xcode-plugin/pull/74), [JENKINS-42457](https://issues.jenkins-ci.org/browse/JENKINS-42457){.issue-link}, [JENKINS-33355](https://issues.jenkins-ci.org/browse/JENKINS-33355){.issue-link})

#### Version 1.4.11 (21th September 2016)

Because XXXX happens

-   Fix: Support configurable ID for developer profile (JENKINS-32987)

#### Version 1.4.10 (20th September 2016)

-   New: Support configurable ID for developer profile (JENKINS-32987)
-   New: Allow the option not to sign the IPA with xcrun (JENKINS-32370)
-   Fix: use textarea for Xcode Build Arguments (JENKINS-30228)
-   Fix: Generating an archive builds the project twice (JENKINS-30362)
-   Fix: Allowed the use of environment variables in plist url
    (JENKINS-27236)

#### Version 1.4.9 (23rd September 2015)

-   Fix: only prepend -allTargets for -project builds (JENKINS-28256)
-   New: Add support for Xcode 7 date format in Unit Testing build task
    (pull request xcode-plugin/63)

#### Version 1.4.8 (28th February, 2015)

-   Fix: Add timeout to xcodebuild -list to avoid hang on xcode 6 (pull
    request xcode-plugin/58)
-   New: Support multiple targets to be passed into xcodebuild (pull
    request xcode-plugin/43)

#### Version 1.4.7 (5th January, 2015)

-   Fix: XCTest output parsing: support nested/namespaced test suites
    (JENKINS-26295)
-   New: XCTest output parsing: handle tests suites exiting with an
    error (pull request xcode-plugin/54)

#### Version 1.4.6 (16th December, 2014)

-   Fix: broken dSYM packaging (since 1.4.5)
-   Fix: BUILD\_DATE does not produce the correct last modified date if
    built on a slave machine (pull request xcode-plugin/50)
-   Fix: make sure to set provideApplicationVersion properly upon
    upgrade from per-1.4.1 (JENKINS-26027)
-   New: developerProfileLoader: use show-keychain-info to display job
    specific keychain information
-   New: support XC test output (JENKINS-19955)
-   New: display warning when simulator SDK selected and IPA about to be
    packaged (JENKINS-21293)
-   New: document xcodebuildArguments (JENKINS-13930)

#### Version 1.4.5 (10th December, 2014)

-   Fix: only zip the DSYM if the DSYM file was actually created and
    fail the build if the operation failed
-   Fix: Fail the build if we fail to create an ipa.
-   Fix: "keychain with the same name already exists" (JENKINS-22130)
-   New: XCode 6 compatibility (pull request xcode-plugin/48)
-   New: generate\_manifest added ability to generate enterprise
    distribution manifest plist (pull request xcode-plugin/45)
-   Fix: getKeychain returns a global keychain preferred over path (pull
    request xcode-plugin/41)
-   New: Ability to change the Bundle identifier (CFBundleIdentifier)
    for an xcode build (pull request xcode-plugin/39)

#### Version 1.4.2 (31st December, 2013)

-   Fix: Avoid NPE on plugin version update (JENKINS-19886, pull request
    xcode-plugin/37)

#### Version 1.4.1 (30th October, 2013)

-   Fix: performance regression in output parsing (JENKINS-20037, pull
    request xcode-plugin/36)

#### Version 1.4 (2nd Oct, 2013)

-   New: added an option to produce .xcarchive (JENKINS-14719)
-   Fix: Fixing show-keychain-info call (JENKINS-xcode-plugin/30)
-   New: Build wrapper to restore the keychain at the end of the build
    (pull request xcode-plugin/31)
-   New: Adding the possibility to provide a pattern for the .ipa file
    name (pull request xcode-plugin/33)
-   New: Added an ability to import \*.developerprofile into a build
    (pull request xcode-plugin/34)
-   New: UI update: group options into 3 categories (pull request
    xcode-plugin/28)
-   New: Introduced the ability to create global keychain configurations
-   New: Add new option "allow failing build results" (pull request
    xcode-plugin/25)
-   Fix: xcodebuild output parser is more lenient (pull request
    xcode-plugin/19)
-   Fix: Can't add xcodebuild parameters including whitespace
    (JENKINS-12800)
-   New: Add a field for entering code signing identity (pull request
    xcode-plugin/6)

#### Version 1.3.1 (27th March 2012)

-   Fix: Custom xcodebuild arguments values are not persisted
    (JENKINS-12510).

#### Version 1.3 (20th January 2012)

-   New : Ability to specify custom arguments to xcodebuild (so that
    values in project file can be overridden). It is needed to specify
    custom build options to make in-app unit tests work.
-   New : Ability to disable clean up of test reports on per-target
    level, so that it is possible to run several targets in single job
    and not mess-up test reports.
-   Fix : The plugin fails by searching for a double .app extension
    while compressing .dsym (JENKINS-12273)
-   Fix : The plugin fails to delete previous generated IPA results in a
    failed build (JENKINS-12237).
-   Fix : The plugin fails to set default keychain when using an
    alternate (non login) keychain (By default the login keychain is the
    default keychain) (JENKINS-12217).
-   Fix : Restore Java 1.5 runtime compatibility. (JENKINS-12378)

#### Version 1.2.2 (19th December 2011)

-   Fix : Build IPA fails if the plugin is launched on a remote agent
    using a relative path for its FS Root directory (JENKINS-12144)

#### Version 1.2.1 (18th December 2011)

-   Fix : Build IPA switch doesn't work properly for a default Xcode
    project always results in FATAL error (JENKINS-12089)

#### Version 1.2 (8th December 2011)

-   New build parameter to specify the build output directory. This
    overrides the setting in the user's project file, so it will be put
    into a known directory rather than XcodeDerivedData, etc. This makes
    it much easier to set up subsequent build steps in Jenkins that do
    something with the output of the build. It does this by passing the
    setting CONFIGURATION\_BUILD\_DIR to xcodebuild if a path is set for
    this new job config value.
-   Add support for building schemes and workspaces : The plugin now
    supports two extra configuration parameters `xcodeScheme` and
    `xcodeWorkspaceFile`. The scheme maps to xcodebuild's parameter
    "-scheme" and the workspace to "-workspace". The scheme takes
    precedence over the target setting and the workspace takes
    precedence over the project setting.

#### Version 1.1 (29th November 2011)

-   Upgrade the token macro plugin to version 1.5.1 to support
    environment and build variables (JENKINS-11892)
-   New configuration parameter to set the SYMROOT value passed to the
    build. This parameter accepts environment and build variables and
    Macros (JENKINS-11813)
-   Various code cleanup and improvements.

#### Version 1.0.1 (14th November 2011)

-   Minor fix about the default value and the documentation of the
    keystore path parameter.

#### Version 1.0 (14th November 2011)

-   Initiated from [Ray Yamamoto Hilton's Xcode plugin for
    Hudson](http://rayh.com.au/xcode-hudson-plugin) with few changes :
    -   It improves jenkins compatibility, and is available in its
        update center.
    -   It uses the to configure values of `CFBundleVersion` and
        `CFBundleShortVersionString`
    -   It allows to configure the keychain to use and to unlock it
    -   It is ready for internationalization

If you previously used the version provided by Ray you should be able to
test this one in parallel as it has a new identity. Also you'll have to
reconfigure a large part of it if you want to upgrade thus don't forget
to save your settings.



================================================
FILE: Jenkinsfile
================================================
buildPlugin(platforms: ['linux'])


================================================
FILE: README.md
================================================
Xcode plugin
------------

This plugin adds the ability to call Xcode command line tools to automate build and packaging iOS applications (iPhone, iPad, ...).
*  Report all issues or features requests in Jira : https://issues.jenkins-ci.org/issues/?jql=component%20%3D%20xcode-plugin

Contact the Jenkins Community by [mail](http://jenkins-ci.org/content/mailing-lists) or [irc](http://jenkins-ci.org/content/chat) to have support.

*The maintainer is looking for a co-maintainer.
I need your help!!*

To help us maintain the plugin, you can take contact to jerome.lacoste
*at* gmail.com in particular if you are able to test upcoming releases

Thank you!

A problem, An idea ?

*Please use our tasks and issues tracker to report bugs, improvements or
new feature.*

-   [Report a
    bug](https://issues.jenkins-ci.org/secure/CreateIssueDetails!init.jspa?Create=Create&components=16124&pid=10172&issuetype=1)
-   [Ask for a new
    feature](https://issues.jenkins-ci.org/secure/CreateIssueDetails!init.jspa?Create=Create&components=16124&pid=10172&issuetype=2)
-   [Ask for an improvement of an existing
    feature](https://issues.jenkins-ci.org/secure/CreateIssueDetails!init.jspa?Create=Create&components=16124&pid=10172&issuetype=4)

Also if you want to propose some code change using a Github pull
request, please open also a Jira issue. It is easier for developers to
track them.

*Important!*

Newesth version is compatibility with the previous version priour 2.0.12 is maintained.
However, major changes have been made to the handling of macOS
keychains.

Information to access the keychain is moved from configuration to
credentials.  
After that, the information for accessing the keychain must be
registered in the credentials.

This plugin adds the ability to call Xcode command line tools to
automate build and packaging iOS applications (iPhone, iPad, ...).

#### Features

##### Versioning

This builder can invoke agvtool to dynamically update the
`CFBundleVersion` (a.k.a. Technical Version) or
`CFBundleShortVersionString` (a.k.a. Marketing Version). It supports all
macros from the . For example the value `${BUILD_NUMBER`} will be
replaced with the current build number. We advice you to generate a
unique value for each build for the `CFBundleVersion` if you want for
example deploy it into a private store. In that case you can use for
example : `${JOB_NAME}-${BUILD_NUMBER`}

##### Building

The target (optional), configuration (e.g. `Debug`, `Release`) and SDK
(optional) can be specified in the per-project config along with whether
to perform a clean before the build phase.

##### Packaging

The builder can be used to package the .app into a .ipa. Since a .app is
actually a directory, it can be awkward to work with and, especially,
distribute. We can simplify this by packaging the .app into a single
.ipa file, which is just a  
zip file with a well-known internal structure

##### Signing

This plugin has two features that help you simplify the code signing
process.

###### Allowing Jenkins to stage developer profile

This plugin builds on top of to allow you to store your Apple Developer
Profile (\*.developerprofile) file. [This file contains a code signing
private key, corresponding developer/distribution certificates, and
mobile provisioning
profiles](http://stackoverflow.com/questions/15154211/what-data-are-stored-in-developer-profile-file-exported-from-xcode).
You can [create this file from your
XCode](http://stackoverflow.com/questions/10404931/copying-keys-and-certificates-to-another-one-mac-for-iphone-development).

To upload the developer profile into Jenkins, go to "Manage Credentials"
in the system configuration page, and select "Apple Developer Profile"
from the "Add" button. See for further details.

To use this profile for signing, add "Import developer profile" as a
build step before you run xcode, and select the developer profile to
import into the build machine. This build step will install the
developer profile into the slave's keychain.

###### Work with existing populated keychains

If you create a dedicated keychain that stores the code signing private
key and certificate on every build slave, you can configure the plugin
to just unlock this keychain (so that xcode can use it for signing)

Unlocking

If you store your keys in the user keychain (most probably) and if you
run jenkins as daemon, make sure you installed a recent version of
jenkins for Mac, or configured the daemon to create a session (through
the CreationSession=true parameter in your org.jenkins-ci.plist daemon
config file). [See
also](http://stackoverflow.com/questions/9626447/unable-to-sign-ios-builds-with-jenkins)

Timeouts

The keychain has a default timeout of 300 seconds. One can override it
using the security set-keychain-settings command, which isn't supported
in the plugin today. Support in the plugin could be improved by adding
options to modify the timeout as part of the build process. See
[JENKINS-17184](https://issues.jenkins-ci.org/browse/JENKINS-17184).

##### Unit Testing

This plugin will listen to the xcodebuild output when running OCUnit or
XC tests and write out JUnit-format test reports that Jenkins can
understand. Jenkins will then use these to publish test failure reports
and graphs.

##### Sample of the configuration panel

![](docs/images/40d7bd30d112f7b90d88d57fce45ecb2abe29c2e.png)

#### Documentation

##### Installation guide

Obviously, the build machine has to be an OSX machine with XCode
developer tools installed.  
Certificates, Identities and Provisions must be installed on the build
machine separately.  
Just install the latest version of the plugin from the update center and
configure a freestyle job (see \#Usage Guide) that will use your OSX
node (If your central instance isn't running under OSX).  
If xcode related binaries aren't stored in the default location, update
the global configuration of the plugin (Manage Jenkins -\> Configure
System)  
![](docs/images/46781a5731ff4fb8b72f4d780b2b02a402f34a2e.png)

If you want to use multiple versions of Xcode to build your application,
use ’Global Tool Configuration’ to register the distinguished name and
location of the installed Xcode.
![](docs/images/f3e88bf4404d395d55e82786142b77ee217ddbd1.png)

##### Usage guide

###### Import developer profile step

By adding the Import developer profile step to Build, you can import
developer profiles exported to Xcode into temporary keychains or
existing keychains.  
The developer profile contains a set of certificates, secret keys and
provisioning profiles necessary for compiling and signing applications,
which is useful for distributing with multiple Jenkins nodes.

###### Import developer profile configuration parameters

| Parameter                     | Pipeline Parameter         | Since version | Description                                                                                                                                                                                                                                                                                                                                |
|-------------------------------|----------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Developer Profile             | profileId                  | 2.0.1         | Select the developer profile you exported from Xcode Preference to import into the keychain. Developer profile must be registered with Jenkins in advance by "Credentials". If you do not select this column, you can specify the identifier of the developer profile registered in "Credentials" with the next "Developer Profile ID".    |
| Import into existing Keychain | importIntoExistingKeychain | 2.0.6         | If it is checked, the developer profile will be imported into the existing keychain. If not checked, create a new key chain with the file name "jenkins-" + "job name" newly, and import the developer profile into this. (In this case, a random character string is automatically generated and used for the password)                   |
| Target keychain               | keychainId                 | 2.0.13        | The ID of the configured keychain to use to import certificates from developer profile to sign the package.                                                                                                                                                                                                                              |
| Target keychain               | keychainName<br>This has been deprecated and has now been replaced by "keychainId".| 2.0.6         | The name of the configured keychain to use to import certificates from developer profile to sign the package.                                                                                                                                                                                                                              |
| Keychain path                 | keychainPath               | 2.0.6         | Keychain path to import developer profile.                                                                                                                                                                                                                                                                                                 |
| Keychain password             | keychainPwd                | 2.0.6         | Password to unlock keychain importing developer profile.                                                                                                                                                                                                                                                                                   |

Limitations

The Xcode Integration Plugin has the function of importing the secret
key and certificate of the developer account into the temporary key
chain, but as the constraint of macOS can not handle different key chain
for each session, the job handling the key chain If you execute them in
parallel, this will not work properly.

As one of workarounds, it is impossible to limit the maximum number of
jobs around Jenkins' node to 1 and to execute multiple nodes with
different macOS accounts.  

###### Setting up a build step

Add the XCode build step to a free-style project and set the target
(e.g. `MyApp`), configuration (e.g. `Release`) and check the build IPA
and update version number options. This will give you a single,
versioned .ipa file. You can also select to clean the project before a
build; while this will make sure that the project is starting from a
clean state, it will make large projects take a lot longer.

###### Setting up a unit test step

Add the XCode build step and this time specify your unit test target
(e.g. `MyAppTests`), configuration (e.g. `Debug`) and the SDK (e.g.
`Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.1.sdk/`).  
Leave all the checkboxes unselected. The SDK needs to be supplied here
as the unit tests will only be run when building under the simulator's
SDK.  
Check the "Publish JUnit test result report" option in the project
config and set the value `"*``/test-reports/``*.xml"` under "Test report
XMLs". This will tell Jenkins to pick up the JUnit-format test reports.

###### XCode Builder configuration parameters

| Parameter                     | Pipeline Parameter        | Since version | Description                                                                                                                                                                                                                                                                                                                                |
|-------------------------------|---------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|Xcode Workspace File           |xcodeWorkspaceFile         |1.2            |Only needed if you want to compile a workspace instead of a project. It takes precedence over 'Xcode Project File' setting and this job 'configuration' parameter."|
|Xcode Tools Version            |xcodeName                  |2.0.3	        |You can select the version of Xcode set by 'Global Tool Configuration' by plugin setting.<br>If you choose the 'System Default' for Xcode version, plugin will not do anything, so you can switch Xcode using environment variable 'DEVELOPER_DIR' as well.   
|Xcode Schema File	            |xcodeSchema	            |1.2	        |Needed if you want to compile for a specific schema instead of a target, or if you want to generate an archive or an IPA.|
|Xcode Project File             |xcodeProjectFile       	|1.0            |If there is more than one XCode project file in the project path, you will need to specify the file name of the project you wish to build.<br>If you need to build all project, you will need to create an XCode build step for each one manually.|
|Xcode Project Directory        |xcodeProjectPath	        |1.0            |This is the relative path from the workspace to the directory that contains the XCode project file.<br>You only need to supply this value if the XCode project you wish to build is not in the root of the workspace.|
|Use Legacy Build System?   	|useLegacyBuildSystem	    |2.0.9      	|Use the old 'Legacy Build System' instead of 'New Build System' of Xcode 9 and later.|
|Upload Symbols?	            |uploadSymbols	            |2.0.3	        |If Checked, include symbols in IPA exporting for App Store.<br>The default is "Yes" (check is on).|
|Upload Bitcode?	            |uploadBitcode	            |2.0.3	        |If Checked, include bitcode in IPA exporting for App Store.<br>The default is "Yes" (check is on).|
|Unlock Keychain?           	|unlockKeychain	            |1.0	        |Automatically unlock the keychain before signing the archive?|
|Thinning	                    |thinning	                |2.0.3          |Set this to thin the packages for one or more devices in Xcode when exporting IPA by methods other than App Store.<br><br>Available options are:<br><br>- \<none> (Xcode export non-thinned generic application),<br>- <thin-for-all-variants> (Xcode export universal applications and all available thinning variants),<br> -Or for a model identifier a specific device (eg "iPhone 7, 1").<br>The default is \<none>.|
|Technical version	            |cfBundleVersionValue   	|1.0            |This will set the CFBundleVersion to the specified string. Supports all macros and also environment and build variables from the Token Macro Plugin. For example the value ${BUILD_NUMBER} will be replaced with the current build number. We advice you to generate a unique value for each build if you want for example deploy it into a private store. In that case you can use for example : ${JOB_NAME}-${BUILD_NUMBER}|
|Target                     	|target	                    |1.0            |The target to build. If left empty, this will build all targets in the project. If you wish to build your binary and the unit test module, it is best to do this as two separate steps each with their own target. This was, the iPhone Simulator SDK can be specified for the unit tests.|
|SYMROOT                        |symRoot                    |1.1            |You only need to supply this value if you want to specify the SYMROOT path to use. If empty, the default SYMROOT path will be used (it could be different depending of your Xcode version). Supports all macros and also environment and build variables from the Token Macro Plugin. For example you can use the value : ${WORKSPACE}/build|
|Strip Swift Symbols?	        |stripSwiftSymbols	        |2.0.5	        |If checked, symbols be stripped from Swift libraries when exporting the application to IPA.|
|SDK	                        |sdk                    	|1.0            |You only need to supply this value if you want to specify the SDK to build against. If empty, the SDK will be determined by XCode. If you wish to run OCUnit tests, you will need to use the iPhone Simulator's SDK, for example: /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.1.sdk/|
|ResultBundlePath           	|resultBundlePath          	|2.0.11	        |Leave empty, it will not output a test result and will not analyze the test results. relative to the project-directory.|
|Provisioning profiles UUID	    |provisioningProfiles: [provisioningProfileUUID]    |2.0.1	|Specify the UUID or Specifire of the provisioning profile to use to sign the application. If the location of the provisioning profile is set instead of the UUID or Specifire, read the UUID from the provisioning profile and use that value.     
|Provisioning Profiles Bundle ID|provisioningProfiles: [provisioningProfileAppId]	|2.0.1	|Specify the Bundle ID of the application for which code sign to be performed.<br>If the location of the Info.plist file contained in the compiled archive is set instead of the Bundle ID, read the Bundle ID from the Info.plist file and use that value.<br>Provide version number and run avgtool?	provideApplicationVersion	1.4	Provide version number and run avgtool before invoking the build.
|Pack on demand resources?      |~~embedOnDemandResourcesAssetPacksInBundle~~<br>assetPacksInBundle|	2.0.3	|Export settings for non App Store.<br>If the application is using on demand resources and this item is on, the asset pack is included in the application bundle, so you can test the app without the server hosting the asset pack.<br>If assetPacksBaseURL is not specified, the default is YES (check is on).|
|Pack application, build and sign .ipa?	|buildIpa	        |1.0	        |The target to build. If left empty, this will build all targets in the project. If you wish to build your binary and the unit test module, it is best to do this as two separate steps each with their own target. This was, the iPhone Simulator SDK can be specified for the unit tests.|
|Output directory	            |ipaOutputDirectory	        |1.4	        |The output directory for the .ipa file, relative to the build directory.|
|On demand resources asset URL	|~~onDemandResourcesAssetPacksBaseURL~~<br>assetPacksBaseURL	|2.0.3	|Export settings for non-App Store.<br>If the application is using an on demand resource and assetPacksInBundle is not YES, this must be the base URL that specifies the host of the asset pack. This will set up the app to download the asset pack from the specified URL. |
|No Console Log?	            |noConsoleLog	            |2.0.1	        |Checking this option will not log xcode build output to console output.|
|New bundle ID	                |bundleID	                |1.4	        |The new bundle ID. Usually something like com.companyname.projectname.|
|Marketing version	            |cfBundleShortVersionStringValue|1.0        |This will set the CFBundleShortVersionString to the specified string. Supports all macros and also environment and build variables from the Token Macro Plugin.|
|Manual signing?	            |manualSigning<br>This has been deprecated and has now been replaced by "signingMethod".|2.0.1	|For this option you need to manually specify the combination of Provisioning profile UUID and BundleID.<br>This will be useful if you want to change the combination of Provisioning Profile and Certificate used for CodeSign when you build the application.|
|Manifest Plist URL         	|ipaManifestPlistUrl	    |1.5	        |The base URL to use to create a Manifest Plist. If omitted no Manifest Plist will be generated.|
|Logfile Output directory   	|logfileOutputDirectory	    |2.0.1	        |Specify the directory to output the log of xcodebuild.<br>If you leave it blank, it will be output to "project directory/builds/${BUILD_NUMBER}/log" with other logs.<br>If an output path is specified, it is output as a xcodebuild.log file in a relative directory under the "build output directory"|
|Keychain path	                |keychainPath	            |1.0	        |The path of the keychain to use to retrieve certificates to sign the package (default : ${HOME}/Library/Keychains/login.keychain).|
|Keychain password	            |keychainPwd	            |1.0	        |The password of the keychain to use to retrieve certificates to sign the package.|
|Keychain Id	                |keychainId<br>             |2.0.13	        |The ID of the configured keychain to use to retrieve certificates to sign the package.|
|Keychain name	                |keychainName<br>This has been deprecated and has now been replaced by "keychainId".|1.4	        |The name of the configured keychain to use to retrieve certificates to sign the package.|
|Interpret As Regular Expression|interpretTargetAsRegEx	    |1.4	        |Build all entries listed under the "Targets:" section of the xcodebuild -list output that match the regexp.|  
|Info.plist path	            |bundleIDInfoPlistPath  	|1.4	        |The path to the info.plist file which contains the CFBundleIdentifier of your project.<br>Usually something like:<br>${WORKSPACE}/ProjectName/Project-Info.plist|
|Generate Archive?          	|generateArchive	        |2.0	        |Checking this option will generate an xcarchive of the specified scheme. A workspace and scheme are are also needed for archives.|
|Full size image URL	        |fullSizeImageURL	        |2.0.3      	|Export settings for non App Store.<br>Specify the URL of the image (512 x 512 pixels) of the icon to be displayed when installing the application using manifest.plist.|
|Export method	                |ipaExportMethod	        |1.4	        |The export method of the .app to generate the .ipa file. Should be one in 'development', 'ad-hoc', 'enterprise' or 'app-store'.|
|Display image URL          	|displayImageURL	        |2.0.3	        |Export settings for non App Store.<br>Specify the URL of the image (57 x 57 pixels) of the icon to be displayed when installing the application using manifest.plist.|
|Development Team ID        	|developmentTeamID	        |1.4	        |The ID of the Apple development team to use to sign the IPA If 'Development Team' is not selected.|
|Development Team	            |developmentTeamName	    |1.4        	|The name of the configured development team to use to sign the package. As of XCode 8.3, this is required now to sign an ipa (which now uses xcodebuilder).<br>A development team can be configured here by specifying a Development Team ID, or by creating one in the jenkins global configuration.|
|Custom xcodebuild arguments	|xcodebuildArguments	    |1.3	        |Passing custom arguments is convenient when you need to change some project options for Jenkins build, but don't want them to persist in project file. For example when running application tests, following settings often are nice fit: GCC_SYMBOLS_PRIVATE_EXTERN=NO COPY_PHASE_STRIP=NO. Otherwise Release build will usually fail because it won't be able to find application symbols to link with test bundle. Arguments are currently separated by space, enclosing them in quotes won't help.|
|Copy provisioning profile  	|copyProvisioningProfile	|2.0.7      	|If Checked, and the filename of provisioning profile is specified in "Provisioning profile UUID", the specified file is copied to a predetermined place. ("/Users/${HOME}/Library/MobileDevice/Provisioning Profiles/")<br>This can be used to overwrite the contents of the developer profile or system settings in the provisioning profile in the project deployed from SCM etc.<br>If the provisioning profile UUID or Specifire is set in "provisioning profile UUID", it does not do anything.<br>The default is "Yes" (check is on)|
|Configuration	                |configuration	            |1.0	        |This is the name of the configuration as defined in the XCode project. By default there are Debug and Release configurations.|
|Compile Bitcode?	            |compileBitcode	            |2.0.3      	|If checked, Xcode will recompiling Bitcode and exporting IPA for the non App Store.<br>The default is "Yes" (check is on).|
|Code signing settings	        |signingMethod	            |2.0.7      	|This attribute can take one of the following three values.<br>"automatic" (Check "Automatic Signing")<br>Checking this option will automatically generate Provisioning Profile and certificates for signing application.<br>However, please be aware that using this function will automatically create Provisioning profile and certificates as necessary, so that old Provisioning profile and certificates will be invalid at that time.<br>"manual" (Check "Manual signing")<br>For this option you need to manually specify the combination of Provisioning profile UUID and BundleID.<br>This will be useful if you want to change the combination of Provisioning Profile and Certificate used for CodeSign when you build the application.<br>"readFromProject" (Check "Read from Xcode Project")<br>With this option, it automatically retrieve and sets the combination of BundleID and Provisioning profile UUID from the Xcode project file.<br>This is useful when you want to take over the combination of BundleID and Provisioning profile UUID that you used in the Xcode project (GUI).|
|Clean test reports?	        |cleanTestReports	        |1.3	        |This will delete the processed test reports before invoking the build. Usually it is a good idea only to do it in test targets, otherwise if other Xcode target is built before tests – the build will fail to collect test reports.|
|Clean ResultBundlePath?    	|cleanResultBundlePath	    |2.0.11     	|This will delete the ResultBundlePath before invoking the build.|
|Clean before build?	        |cleanBeforeBuild	        |1.0            |This will delete the build directories before invoking the build. This will force the rebuilding of ALL dependencies and can make large projects take a lot longer.|
|Change bundle ID?	            |changeBundleID	            |1.4	        |Checking this option will replace the bundle identifier.<br>You will need to specify which bundle ID (CFBundleIdentifier) to use and where is the Info.plist file located.<br>This is handy for example when you want to use a different code signing identity in your development projects.|
|Build output directory         |buildDir	                |1.2            |The value to use for CONFIGURATION_BUILD_DIR setting (BUILD_DIR in >= 2.0.0). You only need to supply this value if you want the product of the XCode build to be in a location other than the one specified in project settings and this job 'SYMROOT' parameter. Supports all macros and also environment and build variables from the Token Macro Plugin. For example you can use the value : ${WORKSPACE}/build|
|Asset pack URL	                |assetPackManifestURL	    |2.0.3	        |Export settings for non-App Store App.<br>If the application is using on-demand resources and the application will installing OTA with manifest.plist, this must be the base URL that specifies the host of the asset pack. This will set up the app to download the asset pack from the specified URL.|
|Application URL	            |appURL	                    |2.0.3	        |Specify the URL for installing the application when creating the manifest.plist that is necessary when OTA installing the application from Web pages or email.|
|Allow failing build results?   |allowFailingBuildResults	|1.4	        |Checking this option will prevent this build step from failing if xcodebuild exits with a non-zero return code.|
|.ipa filename pattern	        |ipaName	                |1.4	        |A pattern for the ipa file name. You may use ${VERSION} and ${BUILD_DATE} (yyyy.MM.dd) in this string|

###### Setting up a Export IPA step

If you add the Export IPA step and set up the information necessary for
exporting the IPA file, the location of the archive, the export method,
code signature information, etc., you can export the IPA from the
archive output in the Xcode Build step.

###### Export IPA configuration parameters

| Parameter                     | Pipeline Parameter        | Since version | Description                                                                                                                                                                                                                                                                                                                                |
|-------------------------------|---------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|Development Team	            |developmentTeamName	    |2.0.1	        |The name of the configured development team to use to sign the package. As of XCode 8.3, this is required now to sign an ipa (which now uses xcodebuilder).<br>A development team can be configured here by specifying a Development Team ID, or by creating one in the jenkins global configuration.|
|Development Team ID	        |developmentTeamID	        |2.0.1	        |The ID of the Apple development team to use to sign the IPA If 'Development Team' is not selected.
|Xcode Tools Version	        |xcodeName	                |2.0.3	        |You can select the version of Xcode set by 'Global Tool Configuration' by plugin setting.<br>If you choose the 'System Default' for Xcode version, plugin will not do anything, so you can switch Xcode using environment variable 'DEVELOPER_DIR' as well.   
|Archive directory	            |archiveDir	                |2.0.1	        |Specify the location of the path (usually BUILD_DIR specified by xcodebuild) to read the Archive for exporting the IPA file.<br>Supports all macros and also environment and build variables from the Token Macro Plugin.<br><br>For example you can use the value :<br>${WORKSPACE}/build
|Export method	                |ipaExportMethod	        |2.0.1	        |The export method of the .app to generate the .ipa file. Should be one in 'development', 'ad-hoc', 'enterprise' or 'app-store'.
|.ipa filename pattern	        |ipaName	                |2.0.1	        |A pattern for the ipa file name. You may use ${VERSION} and ${BUILD_DATE} (yyyy.MM.dd) in this string
|Output directory	            |ipaOutputDirectory	        |2.0.1	        |The output directory for the .ipa file, relative to the build directory.
|Upload Bitcode?	            |uploadBitcode	            |2.0.3	        |If Checked, include bitcode in IPA exporting for App Store.<br>The default is "Yes" (check is on).
|Upload Symbols?	            |uploadSymbols	            |2.0.3	        |If Checked, include symbols in IPA exporting for App Store.<br>The default is "Yes" (check is on).
|Compile Bitcode?	            |compileBitcode	            |2.0.3	        |If checked, Xcode will recompiling Bitcode and exporting IPA for the non App Store.<br>The default is "Yes" (check is on).
|Thinning	                    |thinning	                |2.0.3	        |Set this to thin the packages for one or more devices in Xcode when exporting IPA by methods other than App Store.<br><br>Available options are:<br>    <none> (Xcode export non-thinned generic application),<br>    <thin-for-all-variants> (Xcode export universal applications and all available thinning variants),<br>    Or for a model identifier a specific device (eg "iPhone 7, 1").<br><br>The default is <none>.
|Pack on demand resources?	    |assetPacksInBundle         |2.0.3	        |Export settings for non App Store.<br>If the application is using on demand resources and this item is on, the asset pack is included in the application bundle, so you can test the app without the server hosting the asset pack.<br>If assetPacksBaseURL is not specified, the default is YES (check is on).
|On demand resources asset URL	|assetPacksBaseURL	        |2.0.3	        |Export settings for non-App Store.<br>If the application is using an on demand resource and assetPacksInBundle is not YES, this must be the base URL that specifies the host of the asset pack. This will set up the app to download the asset pack from the specified URL. 
|Application URL	            |appURL	                    |2.0.3	        |Specify the URL for installing the application when creating the manifest.plist that is necessary when OTA installing the application from Web pages or email.
|Display image URL	            |displayImageURL	        |2.0.3	        |Export settings for non App Store.<br>Specify the URL of the image (57 x 57 pixels) of the icon to be displayed when installing the application using manifest.plist.
|Full size image URL	        |fullSizeImageURL	        |2.0.3	        |Export settings for non App Store.<br>Specify the URL of the image (512 x 512 pixels) of the icon to be displayed when installing the application using manifest.plist.
|Asset pack URL	                |assetPackManifestURL	    |2.0.3	        |Export settings for non-App Store App.<br>If the application is using on-demand resources and the application will installing OTA with manifest.plist, this must be the base URL that specifies the host of the asset pack. This will set up the app to download the asset pack from the specified URL.
|trip Swift Symbols?	        |stripSwiftSymbols	        |2.0.5	        |If checked, symbols be stripped from Swift libraries when exporting the application to IPA.
|Manual signing?                |manualSigning<br>This has been deprecated and has now been replaced by "signingMethod".|2.0.1|For this option you need to manually specify the combination of Provisioning profile UUID and BundleID.<br>This will be useful if you want to change the combination of Provisioning Profile and Certificate used for CodeSign when you build the application.
|Code signing settings	        |signingMethod	            |2.0.7	        |This attribute can take one of the following three values.<br>- "automatic" (Check "Automatic Signing")<br>Checking this option will automatically generate Provisioning Profile and certificates for signing application.<br>However, please be aware that using this function will automatically create Provisioning profile and certificates as necessary, so that old Provisioning profile and certificates will be invalid at that time.<br>- "manual" (Check "Manual signing")<br>For this option you need to manually specify the combination of Provisioning profile UUID and BundleID.<br>This will be useful if you want to change the combination of Provisioning Profile and Certificate used for CodeSign when you build the application.<br>- "readFromProject" (Check "Read from Xcode Project")<br>With this option, it automatically retrieve and sets the combination of BundleID and Provisioning profile UUID from the Xcode project file.<br>This is useful when you want to take over the combination of BundleID and Provisioning profile UUID that you used in the Xcode project (GUI).
|Provisioning Profiles Bundle ID|provisioningProfiles: [provisioningProfileAppId]|2.0.1|Specify the Bundle ID of the application for which code sign to be performed.<br>If the location of the Info.plist file contained in the compiled archive is set instead of the Bundle ID, read the Bundle ID from the Info.plist file and use that value.     
|Provisioning profiles UUID	    |provisioningProfiles: [provisioningProfileUUID]|2.0.1|Specify the UUID or Specifire of the provisioning profile to use to sign the application. If the location of the provisioning profile is set instead of the UUID or Specifire, read the UUID from the provisioning profile and use that value.     
|Unlock Keychain?	            |unlockKeychain	            |2.0.1	        |Automatically unlock the keychain before signing the archive?
|Copy provisioning profile	    |copyProvisioningProfile	|2.0.7	        |If Checked, and the filename of provisioning profile is specified in "Provisioning profile UUID", the specified file is copied to a predetermined place. ("/Users/${HOME}/Library/MobileDevice/Provisioning Profiles/")<br>This can be used to overwrite the contents of the developer profile or system settings in the provisioning profile in the project deployed from SCM etc.<br>If the provisioning profile UUID or Specifire is set in "provisioning profile UUID", it does not do anything.<br>The default is "Yes" (check is on)
|Keychain name	                |keychainName	            |2.0.1	        |The name of the configured keychain to use to retrieve certificates to sign the package.
|Keychain name	                |keychainName	            |2.0.1	        |The name of the configured keychain to use to retrieve certificates to sign the package.
|Keychain path	                |keychainPath	            |2.0.1	        |The path of the keychain to use to retrieve certificates to sign the package (default : ${HOME}/Library/Keychains/login.keychain).
|Keychain password	            |keychainPwd	            |2.0.1	        |The password of the keychain to use to retrieve certificates to sign the package.
    
#### Compiling Xcode projects and exporting IPApackages using Jenkins's Pipeline function
    
1.  Import developer profile.

    ``` syntaxhighlighter-pre
            importDeveloperProfile(importIntoExistingKeychain: false,
                profileId: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX')
    ```

2.  Build the project and output the archive.

    ``` syntaxhighlighter-pre
            xcodeBuild(
              xcodeSchema: "${PROJECT_SCHEMA}",
              ipaOutputDirectory: 'Release',
              ipaExportMethod: 'app-store',
              generateArchive: true,
              buildIpa: true,
              ipaName: "${BUILD_TARGET}",
              bundleID: 'com.example.TargetApp',
              developmentTeamName: "${DEVELOPMENT_TEAM_NAME}",
              cleanBeforeBuild: true,
              configuration: 'Release',
              cfBundleShortVersionStringValue: '1.0.0',
              cfBundleVersionValue: '1'
            )
    ```

3.  Export the IPA file from the archive.

    ``` syntaxhighlighter-pre
        exportIpa(
            archiveDir: "${WORKSPACE}/${repositoryName}/build/Release-iphoneos",
            xcodeSchema: "${PROJECT_SCHEMA}",
            developmentTeamName: "${DEVELOPMENT_TEAM}",
            configuration: "AdHoc",
            infoPlistPath: "${INFO_PLIST}",
            manualSigning: true,
            provisioningProfiles: [
                [provisioningProfileAppId: "${BUNDLE_ID}", provisioningProfileUUID: 'TestApp_AdHoc_Profile.mobileprovision']
                [provisioningProfileAppId: "${BUNDLE_ID}.watchkitapp", provisioningProfileUUID: 'TestApp_AdHoc_Profile.mobileprovision'],
                [provisioningProfileAppId: "${BUNDLE_ID}.watchkitapp.watchkitextension", provisioningProfileUUID: 'TestApp_AdHoc_Profile.mobileprovision']
            ],
            ipaExportMethod: "ad-hoc",
            ipaName: "${BUILD_TARGET}",
            ipaOutputDirectory: "AdHoc"
        )
    ```

4.  Upload the exported IPA file.  

> When using "XCode's" Automatically manage signing ", various ways are required, so please note the points to be noted separately.

#####  Using multiple versions of xcode.

One can easily support multiple versions by using environment variables.
But first one need to install multiple versions on the build server.
Here's one strategy:

###### install multiple versions of xcode

0\. Note current config.

xcode-select -p

1\. download xcode DMGs from <http://developer.apple.com/downloads/>

2\. enable install from everywhere (under System preferences / Security)

Without that I had problems installing xcode, without graphical
feedback, tested on 10.9.5, freshly booted.

Symptoms were:

-   app not responsive
-   Getting errors like in /var/log/system.log

Someone attempted to start application App:"Xcode" asn:0x0-1b62b61
pid:57656 refs=6 @ 0x7fa5d9f6df40 but it still has
\_kLSApplicationLockedInStoppedStateKey=true, so it is is staying
stopped. : LASApplication.cp \#2468 SetApplicationInStoppedState()
q=LSSession 100027/0x186bb queue

3\. open DMG file, copy app to /Applications. This might take a while.

4\. close /Volumes/Xcode (otherwise installation won't start)

5\. start Xcode, accept agreement, install missing packages if necessary.
This might take a while. Close xcode after GUI opens.

6\. move freshly installed Xcode to new path, e.g.

sudo mv /Applications/Xcode.app /Applications/Xcode6.1.app

(I use this so that the xcode app appears with version number under
spotlight)

7\. reset default xcode-select if necessary (installation might have
changed it / reset to /Applications/Xcode.app)

sudo xcode-select -s /Applications/Xcode6.1.app

(Note the part above could be fully automated....)

###### Select the xcode version at runtime

1\. Use EnvInject plugin  
2. for jobs that require the non default do something like

DEVELOPER\_DIR=/Applications/Xcode6.0.1.app/Contents/Developer

under Inject environment variables to the build process

###### Select the xcode version at runtime (Version 2.0.3 or later)

1. Register the distinguished name and location of the installed Xcode
using ’Global Tool Configuration’.  
2. Select Xcode registered in 'Global Tool Configuration' in Job's
'Xcode Tools Version'.

That's it.

#### FAQ

##### User interaction is not allowed

When code-signing, a prompt may appear on the build machine asking
whether to allow keychain access.  
This will block the build with a message like
`"User interaction is not allowed"` until it is dismissed.  
Just select 'Always Allow' the first time and it shouldn't need to ask
again.  
![](docs/images/308d472628999c9f1961068c9af34e49a31c76c7.png)

If this prompt is not showing on the build machine, you can force it to
appear by running the codesign command that failed from a terminal on
the build machine:   /usr/bin/codesign --force --sign "iPhone
Distribution: .....

##### No Xcode folder is set

\[sources\] $ /usr/bin/xcodebuild -version xcode-select: Error: No Xcode
folder is set. Run xcode-select -switch \<xcode\_folder\_path\> to set
the path to the Xcode folder. Error: /usr/bin/xcode-select returned
unexpected error. FATAL: Check your XCode installation. Jenkins cannot
retrieve its version.

You probably just installed XCode (by default it is in `/Developer`) but
its path isn't configured. You can fix it with

xcode-select -switch /Developer/

You should now be able to execute `xcodebuild`. Ex :

host:\~ user$ /usr/bin/xcodebuild -version Xcode 4.2 Build version 4C199

##### Xcode 4.3

XCode 4.3 changes [2
things](https://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/WhatsNewXcode/Articles/xcode_4_3.html)
that are important for our usage on a slave or a master :

-   **Command-Line Tools Are Optional** : The command-line tools are not
    bundled with Xcode 4.3 by default. Instead, they have to be
    installed using the Components tab of the Downloads preferences
    panel
    ![](docs/images/8f2803dc1d2d272296cfa2ba044a3286e29a374c.jpg)
-   **/Developer No Longer Exists** : You may have to reconfigure its
    path like this:

    sudo xcode-select -switch
    /Applications/Xcode.app/Contents/Developer/


================================================
FILE: pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ The MIT License
  ~
  ~ Copyright (c) 2011 Ray Yamamoto Hilton
  ~
  ~ Permission is hereby granted, free of charge, to any person obtaining a copy
  ~ of this software and associated documentation files (the "Software"), to deal
  ~ in the Software without restriction, including without limitation the rights
  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ~ copies of the Software, and to permit persons to whom the Software is
  ~ furnished to do so, subject to the following conditions:
  ~
  ~ The above copyright notice and this permission notice shall be included in
  ~ all copies or substantial portions of the Software.
  ~
  ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  ~ THE SOFTWARE.
  -->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.jenkins-ci.plugins</groupId>
    <artifactId>plugin</artifactId>
    <version>4.41</version>
    <relativePath />
  </parent>
  <artifactId>xcode-plugin</artifactId>
  <version>${revision}-${changelist}</version>
  <packaging>hpi</packaging>
  <name>Xcode integration</name>
  <description>This plugin adds the ability to call Xcode command line tools to automate build and packaging iOS applications (iPhone, iPad, ...).</description>
  <url>https://github.com/jenkinsci/xcode-plugin</url>
  <licenses>
    <license>
      <name>MIT</name>
      <url>LICENSE.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <developers>
    <developer>
      <id>rayhilton</id>
      <name>Ray Yamamoto Hilton</name>
      <email>ray.hilton@gmail.com</email>
    </developer>
    <developer>
      <id>aheritier</id>
      <name>Arnaud Heritier</name>
      <email>aheritier@apache.org</email>
    </developer>
    <developer>
      <id>lacostej</id>
      <name>Jerome Lacoste</name>
      <email>jerome.lacoste@gmail.com</email>
    </developer>
    <developer>
      <id>kazuhidet</id>
      <name>Kazuhide Takahashi</name>
      <email>kazuhide.t@linux-powered.com</email>
    </developer>
  </developers>
  <scm>
    <connection>scm:git:https://github.com/${gitHubRepo}.git</connection>
    <developerConnection>scm:git:git@github.com:${gitHubRepo}.git</developerConnection>
    <url>https://github.com/${gitHubRepo}</url>
    <tag>${scmTag}</tag>
  </scm>
  <repositories>
    <repository>
      <id>repo.jenkins-ci.org</id>
      <url>https://repo.jenkins-ci.org/public/</url>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>repo.jenkins-ci.org</id>
      <url>https://repo.jenkins-ci.org/public/</url>
    </pluginRepository>
  </pluginRepositories>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.jenkins.tools.bom</groupId>
        <artifactId>bom-2.319.x</artifactId>
        <version>1466.v85a_616ea_b_87c </version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>credentials</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>token-macro</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jenkins-ci.plugins.workflow</groupId>
      <artifactId>workflow-cps</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>com.googlecode.plist</groupId>
      <artifactId>dd-plist</artifactId>
      <version>1.23</version>
    </dependency>
    <dependency>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>structs</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jenkins-ci.plugins</groupId>
      <artifactId>credentials-binding</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jenkinsci.plugins</groupId>
      <artifactId>pipeline-model-extensions</artifactId>
    </dependency>
    <dependency>
      <groupId>org.jenkinsci.plugins</groupId>
      <artifactId>pipeline-model-definition</artifactId>
    </dependency>
    <dependency>
      <groupId>org.bouncycastle</groupId>
      <artifactId>bcpkix-jdk15on</artifactId>
      <version>1.70</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.jenkins.plugins</groupId>
      <artifactId>jaxb</artifactId>
      <version>2.3.6-1</version>
    </dependency>
  </dependencies>
  <properties>
    <revision>2.0.17</revision>
    <changelist>999999-SNAPSHOT</changelist>
    <gitHubRepo>jenkinsci/xcode-plugin</gitHubRepo>
    <jenkins.version>2.319.1</jenkins.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.jenkins-ci.tools</groupId>
        <artifactId>maven-hpi-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <compatibleSinceVersion>2.0.0</compatibleSinceVersion>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>


================================================
FILE: src/main/java/au/com/rayh/BuildConfiguration.java
================================================
package au.com.rayh;

import com.dd.plist.NSDictionary; 
import com.dd.plist.NSArray;
import com.dd.plist.NSNumber;
import com.dd.plist.NSObject;
import com.dd.plist.NSString;
import com.dd.plist.PropertyListFormatException; 
import com.dd.plist.PropertyListParser; 

public class BuildConfiguration {
  public String uuid;
  public String name;
  public String bundleIdentifier;
  public String infoPlistFile;
  //public String codeSignStyle;
  public String developmentTeamId;
  public String provisioningProfileUUID;
  public String provisioningProfileSpecifier;
  public String productName;

  BuildConfiguration(NSDictionary objectsDict, String buildConfigurationUUID, Boolean automatic) {
    NSDictionary buildConfigurationDict = ((NSDictionary)objectsDict.objectForKey(buildConfigurationUUID.toString()));
    //String baseConfigurationReference = buildConfigurationDict.objectForKey("baseConfigurationReference").toString();
    this.uuid = buildConfigurationUUID.toString();
    this.name = buildConfigurationDict.objectForKey("name").toString();
    System.out.println("buildConfigurationUUID: " + this.uuid);
    NSDictionary buildSettingsDict = ((NSDictionary)buildConfigurationDict.objectForKey("buildSettings"));
    if ( buildSettingsDict == null ) {
      System.out.println("buildSettings not exists!");
      return;
    }
    // LastUpgradeCheck = 0630, CreatedOnToolsVersion = 6.3.1
    if ( buildSettingsDict.objectForKey("PRODUCT_BUNDLE_IDENTIFIER") != null ) {

        this.bundleIdentifier = buildSettingsDict.objectForKey("PRODUCT_BUNDLE_IDENTIFIER").toString();
    }
    else if ( buildSettingsDict.objectForKey("PRODUCT_NAME") != null ) {
        this.productName = buildSettingsDict.objectForKey("PRODUCT_NAME").toString();
    }
    this.infoPlistFile = buildSettingsDict.objectForKey("INFOPLIST_FILE").toString();
    //this.codeSignStyle = buildSettingsDict.objectForKey("CODE_SIGN_STYLE").toString();
    if ( buildSettingsDict.objectForKey("BUNDLE_LOADER") == null && buildSettingsDict.objectForKey("TEST_TARGET_NAME") == null && buildSettingsDict.objectForKey("DEVELOPMENT_TEAM") != null ) {
	this.developmentTeamId = buildSettingsDict.objectForKey("DEVELOPMENT_TEAM").toString();
    }
    if ( !automatic ) {
      this.provisioningProfileUUID = buildSettingsDict.objectForKey("PROVISIONING_PROFILE").toString();
      this.provisioningProfileSpecifier = buildSettingsDict.objectForKey("PROVISIONING_PROFILE_SPECIFIER").toString();
    }
    //else {
    //  this.codeSignStyle = "Automatic";
    //}
  }
}


================================================
FILE: src/main/java/au/com/rayh/DSymFileFilter.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2011 Ray Yamamoto Hilton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package au.com.rayh;

import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;

/**
 *
 * @author lampietti
 */
public class DSymFileFilter implements FileFilter, Serializable {

    public boolean accept(File pathname) {
        return pathname.isDirectory() && pathname.getName().endsWith(".dSYM");
    }
}


================================================
FILE: src/main/java/au/com/rayh/DeveloperProfile.java
================================================
package au.com.rayh;

import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import hudson.Extension;
import hudson.security.ACL;
import hudson.util.IOUtils;
import hudson.util.Secret;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

import jenkins.security.ConfidentialKey;

import org.apache.commons.fileupload.FileItem;
import org.kohsuke.stapler.DataBoundConstructor;

import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;

/**
 * Apple developer profile, which consists of any number of PKCS12 of the private key
 * and the certificate for code signing, and mobile provisioning profiles.
 *
 * @author Kohsuke Kawaguchi
 */
public class DeveloperProfile extends BaseStandardCredentials {
    /**
     * Password of the PKCS12 files inside the profile.
     */
    private Secret password;

    @DataBoundConstructor
    public DeveloperProfile(@CheckForNull CredentialsScope scope, @CheckForNull String id, @CheckForNull String description,
            Secret password, FileItem image) throws IOException {
        super(scope, id, description);
        this.password = password;

        if (image!=null) {
            // for added secrecy, store this in the confidential store
            new ConfidentialKeyImpl(id).store(image);
        }
    }

    @Deprecated
    public DeveloperProfile(String id, String description, Secret password, FileItem image) throws IOException {
        this(CredentialsScope.GLOBAL,id,description,password,image);
    }

    public Secret getPassword() {
        return password;
    }

    /**
     * Retrieves the PKCS12 byte image.
     * @return PKCS12 byte image
     * @throws IOException file I/O
     */
    public byte[] getImage() throws IOException {
        return new ConfidentialKeyImpl(getId()).load();
    }

    /**
     * Obtains the certificates in this developer profile.
     * @return X509Certificates
     * @throws IOException file I/O
     * @throws GeneralSecurityException Certificate error
     */
    public @NonNull List<X509Certificate> getCertificates() throws IOException, GeneralSecurityException {
        try (ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(getImage()))) {
            List<X509Certificate> r = new ArrayList<>();

            ZipEntry ze;
            while ((ze = zip.getNextEntry()) != null) {
                if (ze.getName().endsWith(".p12")) {
                    KeyStore ks = KeyStore.getInstance("pkcs12");
                    ks.load(zip, password.getPlainText().toCharArray());
                    Enumeration<String> en = ks.aliases();
                    while (en.hasMoreElements()) {
                        String s = en.nextElement();
                        Certificate c = ks.getCertificate(s);
                        if (c instanceof X509Certificate) {
                            r.add((X509Certificate) c);
                        }
                    }
                }
            }

            return r;
        }
    }

    public String getDisplayNameOf(X509Certificate p) {
        String name = p.getSubjectDN().getName();
        try {
            LdapName n = new LdapName(name);
            for (Rdn rdn : n.getRdns()) {
                if (rdn.getType().equalsIgnoreCase("CN"))
                    return rdn.getValue().toString();
            }
        } catch (InvalidNameException e) {
            // fall through
        }
        return name; // fallback
    }

    @Extension
    public static class DescriptorImpl extends BaseStandardCredentialsDescriptor {
        @Override
        public String getDisplayName() {
            return "Apple Developer Profile";
        }
    }

    static class ConfidentialKeyImpl extends ConfidentialKey {
        ConfidentialKeyImpl(String id) {
            super(DeveloperProfile.class.getName()+"."+id);
        }

        public void store(FileItem submitted) throws IOException {
            super.store(IOUtils.toByteArray(submitted.getInputStream()));
        }

        public @CheckForNull byte[] load() throws IOException {
            return super.load();
        }
    }

    public static List<DeveloperProfile> getAllProfiles() {
	return CredentialsProvider.lookupCredentials(DeveloperProfile.class, (hudson.model.Item)null, ACL.SYSTEM, Collections.<DomainRequirement>emptyList());
    }
}


================================================
FILE: src/main/java/au/com/rayh/DeveloperProfileLoader.java
================================================
package au.com.rayh;

import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Item;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.remoting.VirtualChannel;
import hudson.security.ACL;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.ArgumentListBuilder;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import hudson.util.Secret;
import jenkins.model.Jenkins;
import jenkins.security.MasterToSlaveCallable;
import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
import org.jenkinsci.plugins.tokenmacro.TokenMacro;

import jenkins.tasks.SimpleBuildStep;
import org.jenkinsci.Symbol;
import org.jenkinsci.remoting.RoleChecker;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import javax.inject.Inject;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
 * Installs {@link DeveloperProfile} into the current slave and unlocks its keychain
 * in preparation for the signing that uses it.
 *
 * TODO: destroy identity in the end.
 *
 * @author Kohsuke Kawaguchi
 */
@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
public class DeveloperProfileLoader extends Builder implements SimpleBuildStep {
    @CheckForNull
    private String profileId;
    @CheckForNull
    private Boolean importIntoExistingKeychain;
    @CheckForNull
    private String keychainId;
    @Deprecated
    @CheckForNull
    private String keychainName;
    @CheckForNull
    private String keychainPath;
    @CheckForNull
    private Secret keychainPwd;
    @CheckForNull
    public String getProfileId() {
        return profileId;
    }

    @DataBoundSetter
    public void setProfileId(String developerProfileId) {
        this.profileId = developerProfileId;
    }

    public Boolean getImportIntoExistingKeychain() {
        return importIntoExistingKeychain == null ? Boolean.valueOf(false) : importIntoExistingKeychain;
    }

    @DataBoundSetter
    public void setImportIntoExistingKeychain(Boolean importIntoExistingKeychain ) {
        this.importIntoExistingKeychain = importIntoExistingKeychain;
    }

    @CheckForNull
    public String getKeychainId() {
        return keychainId;
    }

    @Deprecated
    @CheckForNull
    public String getKeychainName() {
        return keychainName;
    }

    @DataBoundSetter
    public void setKeychainId(String keychainId) {
        this.keychainId = keychainId;
    }

    @Deprecated
    @DataBoundSetter
    public void setKeychainName(String keychainName) {
        this.keychainName = keychainName;
    }

    @CheckForNull
    public String getKeychainPath() {
        return keychainPath;
    }

    @DataBoundSetter
    public void setKeychainPath(String keychainPath) {
        this.keychainPath = keychainPath;
    }

    @CheckForNull
    public Secret getKeychainPwd() {
        return keychainPwd;
    }

    @DataBoundSetter
    public void setKeychainPwd(Secret keychainPwd) {
        this.keychainPwd = keychainPwd;
    }

    @DataBoundConstructor
    public DeveloperProfileLoader() {
    }

    @Deprecated
    public DeveloperProfileLoader(String profileId) {
        this();
	this.profileId = profileId;
    }

    @Override
    public void perform(@NonNull Run<?, ?> run, @NonNull FilePath workspace, @NonNull Launcher launcher, @NonNull TaskListener listener) throws InterruptedException, IOException {
	EnvVars envs = run.getEnvironment(listener);
	String _profileId = envs.expand(this.profileId);
        String _keychainId = envs.expand(this.keychainId);
	String _keychainName = envs.expand(this.keychainName);
	Boolean _importIntoExistingKeychain = this.importIntoExistingKeychain;
        DeveloperProfile dp = getProfile(run.getParent(), _profileId);
        if ( dp == null )
            throw new AbortException(Messages.DeveloperProfile_NoDeveloperProfileConfigured());

        String _keychainPath;
        String _keychainPwd;
        if ( BooleanUtils.isTrue(_importIntoExistingKeychain)) {
            if ( StringUtils.isNotEmpty(_keychainName) ) {
                // for backward compatibility
                listener.getLogger().println(Messages.XCodeBuilder_UseDeprecatedKeychainInfo());
                Keychain keychain = getKeychain(_keychainName);
                if (keychain == null) {
                    throw new AbortException(Messages.DeveloperProfileLoader_NoKeychainInfoConfigured());
                }
                else {
                    _keychainPath = envs.expand(keychain.getKeychainPath());
                    _keychainPwd = envs.expand(Secret.toString(keychain.getKeychainPassword()));
                    _importIntoExistingKeychain = Boolean.valueOf(true);
                }
            }
            else if ( StringUtils.isNotEmpty(_keychainId) ) {
                KeychainPasswordAndPath keychain = getKeychainPasswordAndPath(run.getParent(), _keychainId);
                if ( keychain == null ) {
                    throw new AbortException(Messages.DeveloperProfileLoader_NoKeychainInfoConfigured());
                }
                else {
                    _keychainPath = envs.expand(keychain.getKeychainPath());
                    _keychainPwd = envs.expand(keychain.getPassword().getPlainText());
                    _importIntoExistingKeychain = Boolean.valueOf(true);
                }
            }
            else {
                if ( StringUtils.isNotEmpty(this.keychainPath) && StringUtils.isNotEmpty(Secret.toString(this.keychainPwd)) ) {
                    _keychainPath = envs.expand(this.keychainPath);
                    _keychainPwd = envs.expand(Secret.toString(this.keychainPwd));
                }
                else {
                    throw new AbortException(Messages.DeveloperProfileLoader_KeychainPathOrPasswordIsBlank());
                }
            }
        }
        else {
            // Use temporary keychain with random UUID nasme.
            _keychainPath = "jenkins-" + run.getParent().getFullName().replace('/', '-');
	    _keychainPwd = UUID.randomUUID().toString();
	    _importIntoExistingKeychain = Boolean.valueOf(false);
        }

        // Note: keychain are usualy suffixed with .keychain. If we change we should probably clean up the ones we created

        ArgumentListBuilder args;

        if ( BooleanUtils.isNotTrue(_importIntoExistingKeychain) ) {
	    // if the key chain is already present, delete it and start fresh
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            args = new ArgumentListBuilder("security", "delete-keychain", _keychainPath);
            launcher.launch().cmds(args).stdout(out).join();

            args = new ArgumentListBuilder("security", "create-keychain");
            args.add("-p").addMasked(_keychainPwd);
            args.add(_keychainPath);
            invoke(launcher, listener, args, "Failed to create a keychain");
	}

        args = new ArgumentListBuilder("security", "unlock-keychain");
        args.add("-p").addMasked(_keychainPwd);
        args.add(_keychainPath);
        invoke(launcher, listener, args, "Failed to unlock keychain");

	if ( BooleanUtils.isNotTrue(_importIntoExistingKeychain) ) {
            args = new ArgumentListBuilder("security", "list-keychains");
	    args.add("-d").add("user");
	    args.add("-s").add("login.keychain");
            args.add(_keychainPath);
            invoke(launcher, listener, args, "Failed to set keychain search path");
	}

        final FilePath secret = getSecretDir(workspace, _keychainPwd);
	final byte[] dpImage = dp.getImage();
	if ( dpImage == null )
	    throw new AbortException(Messages.DeveloperProfile_NoDeveloperProfileConfigured());
        secret.unzipFrom(new ByteArrayInputStream(dpImage));

        // import identities
        for ( FilePath id : secret.list("**/*.p12") ) {
            args = new ArgumentListBuilder("security", "import");
            args.add(id).add("-k", _keychainPath);
            args.add("-P").addMasked(dp.getPassword().getPlainText());
            args.add("-T", "/usr/bin/codesign");
            args.add("-T", "/usr/bin/productsign");
            args.add(_keychainPath);
            invoke(launcher, listener, args, "Failed to import identity " + id);
        }

        {
            // display keychain info for potential troubleshooting
            args = new ArgumentListBuilder("security", "show-keychain-info");
            args.add(_keychainPath);
            ByteArrayOutputStream output = invoke(launcher, listener, args, "Failed to show keychain info");
            listener.getLogger().write(output.toByteArray());
        }

	if ( BooleanUtils.isNotTrue(_importIntoExistingKeychain) ) {
            args = new ArgumentListBuilder("security", "set-key-partition-list");
            args.add("-S").add("apple-tool:,apple:");
            args.add("-s").add("-k").addMasked(_keychainPwd);
            args.add(_keychainPath);
            invoke(launcher, listener, args, "Failed to set key partition list to keychain");
        }

	{
	    // If default keychain is not set, set the specified keychain to default keychain.
	    args = new ArgumentListBuilder("security", "default-keychain");
	    ByteArrayOutputStream output = new ByteArrayOutputStream();
	    if ( launcher.launch().cmds(args).stdout(output).join() != 0 ) {
		listener.getLogger().write(output.toByteArray());
		String strResult = new String(output.toByteArray(), "UTF-8");
	        if ( strResult.contains("A default keychain could not be found.") ) {
		    args = new ArgumentListBuilder("security", "default-keychain");
		    args.add("-d").add("user");
		    args.add("-s").add(_keychainPath);
		    invoke(launcher, listener, args, "Failed to set default keychain");
		}
	    }
	}

	if ( BooleanUtils.isNotTrue(_importIntoExistingKeychain) ) {
	    importAppleCert(launcher, listener, workspace, _keychainPath);
	}

        // copy provisioning profiles
        VirtualChannel ch = launcher.getChannel();
        FilePath home = ch.call(new GetHomeDirectory());    // TODO: switch to FilePath.getHomeDirectory(ch) when we can
        FilePath profiles = home.child("Library/MobileDevice/Provisioning Profiles");
        profiles.mkdirs();

        for ( FilePath mp : secret.list("**/*.mobileprovision") ) {
            listener.getLogger().println(Messages.DeveloperProfile_Installing(mp.getName()));
            mp.copyTo(profiles.child(mp.getName()));
        }
    }

    @Override
    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
        perform(build, build.getWorkspace(), launcher, listener);

        return true;
    }

    @Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl) super.getDescriptor();
    }

    public GlobalConfigurationImpl getGlobalConfiguration() {
        return getDescriptor().getGlobalConfiguration();
    }

    public Keychain getKeychain(String keychainName) {
        if ( !StringUtils.isEmpty(keychainName) ) {
            for ( Keychain keychain : getGlobalConfiguration().getKeychains() ) {
                if ( keychain.getKeychainName().equals(keychainName) )
                    return keychain;
            }
        }

        if ( !StringUtils.isEmpty(this.keychainPath) ) {
            Keychain newKeychain = new Keychain();
            newKeychain.setKeychainPath(this.keychainPath);
            newKeychain.setKeychainPassword(this.keychainPwd);
            return newKeychain;
        }

        return null;
    }

    public KeychainPasswordAndPath getKeychainPasswordAndPath(Item context, String keychainId) {
        return (KeychainPasswordAndPath)CredentialsMatchers.firstOrNull(
                CredentialsProvider.lookupCredentials(KeychainPasswordAndPath.class, context,
                        ACL.SYSTEM, Collections.EMPTY_LIST),
                CredentialsMatchers.withId(keychainId));
    }

    public void importAppleCert(Launcher launcher, TaskListener listener, FilePath workspace, String keychainPath) throws IOException, InterruptedException {
	ByteArrayOutputStream out = new ByteArrayOutputStream();
	FilePath homeFolder = workspace.getHomeDirectory(workspace.getChannel());
	String homePath = homeFolder.getRemote();
	String cert = homePath + "/AppleWWDRCA.cer";
	launcher
	    .launch()
	    .cmds("security", "import", cert, "-k", keychainPath)
	    .stdout(out)
	    .join();
	listener.getLogger().write(out.toByteArray());
    }

    private ByteArrayOutputStream invoke(Launcher launcher, TaskListener listener, ArgumentListBuilder args, String errorMessage) throws IOException, InterruptedException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        if (launcher.launch().cmds(args).stdout(output).join()!=0) {
            listener.getLogger().write(output.toByteArray());
            throw new AbortException(errorMessage);
        }
        return output;
    }

    private FilePath getSecretDir(FilePath workspace, String keychainPwd) throws IOException, InterruptedException {
        FilePath secrets = workspace.child("jenkins").child("developer-profiles");
        secrets.mkdirs();
        secrets.chmod(0700);
        return secrets.child(keychainPwd);
    }

    public DeveloperProfile getProfile(Item context, String profileId) {
        return (DeveloperProfile)CredentialsMatchers.firstOrNull(
                CredentialsProvider.lookupCredentials(DeveloperProfile.class, context,
                        ACL.SYSTEM, Collections.EMPTY_LIST),
                CredentialsMatchers.withId(profileId));
    }

    @Extension
    @Symbol("importDeveloperProfile")
    public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
	GlobalConfigurationImpl globalConfiguration;

        @SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
        @Inject
        void setGlobalConfiguration(GlobalConfigurationImpl c) {
            this.globalConfiguration = c;
	}

        @Override
        public boolean isApplicable(Class<? extends AbstractProject> jobType) {
            return true;
        }

        @Override
        public String getDisplayName() {
            return Messages.DeveloperProfile_ImportDeveloperProfile();
        }

        public ListBoxModel doFillProfileIdItems(@AncestorInPath Item context) {
            List<DeveloperProfile> profiles = CredentialsProvider
                    .lookupCredentials(DeveloperProfile.class, context, null);
            ListBoxModel r = new ListBoxModel();
            for (DeveloperProfile p : profiles) {
                r.add(p.getDescription(), p.getId());
            }
            return r;
        }

        public GlobalConfigurationImpl getGlobalConfiguration() {
            return globalConfiguration;
        }

        public String getUUID() {
            return "" + UUID.randomUUID().getMostSignificantBits();
        }

        public FormValidation doCheckDeveloperProfileId(@QueryParameter String value) {
            if ( StringUtils.isEmpty(value) ) {
                return FormValidation.error(Messages.DeveloperProfileLoader_MustSelectDeveloperProfile());
            }
            return FormValidation.ok();
        }

        public FormValidation doCheckKeychainPath(@QueryParameter String value, @QueryParameter String keychainName, @QueryParameter Boolean importIntoExistingKeychain) {
            if ( BooleanUtils.isTrue(importIntoExistingKeychain) ) {
                if ( StringUtils.isEmpty(keychainName) && StringUtils.isEmpty(value) ) {
                    return FormValidation.error(Messages.DeveloperProfileLoader_MustSpecifyKeychainPath());
                }
            }
            return FormValidation.ok();
        }

        public FormValidation doCheckKeychainPwd(@QueryParameter Secret value, @QueryParameter String keychainName, @QueryParameter Boolean importIntoExistingKeychain) {
            if ( BooleanUtils.isTrue(importIntoExistingKeychain) ) {
                if ( StringUtils.isEmpty(keychainName) && StringUtils.isEmpty(Secret.toString(value)) ) {
                    return FormValidation.error(Messages.DeveloperProfileLoader_MustSpecifyKeychainPwd());
                }
            }
            return FormValidation.ok();
        }
    }

    private static final class GetHomeDirectory extends MasterToSlaveCallable<FilePath,IOException> {
        public FilePath call() throws IOException {
            return new FilePath(new File(System.getProperty("user.home")));
        }

        @Override
        public void checkRoles(RoleChecker roleChecker) throws SecurityException {

        }
    }
}


================================================
FILE: src/main/java/au/com/rayh/ExportIpa.java
================================================
package au.com.rayh;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.*;
import hudson.model.*;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.ArgumentListBuilder;
import hudson.util.FormValidation;
import hudson.util.Secret;
import jenkins.tasks.SimpleBuildStep;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;

import javax.inject.Inject;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ExportIpa extends Builder implements SimpleBuildStep {
    private static final String[] VALID_IPA_EXPORT_METHODS = { "development", "ad-hoc", "enterprise", "app-store" };

    @CheckForNull
    private String xcodeProjectPath;
    @CheckForNull
    private String xcodeProjectFile;
    @CheckForNull
    private Boolean unlockKeychain;
    @Deprecated
    @CheckForNull
    private String keychainName;
    @CheckForNull
    private String keychainPath;
    @CheckForNull
    private Secret keychainPwd;
    @CheckForNull
    private String symRoot;
    @CheckForNull
    private String xcodeWorkspaceFile;
    @CheckForNull
    private String xcodeSchema;
    @CheckForNull
    private String archiveDir;
    @CheckForNull
    private String developmentTeamName;
    @CheckForNull
    private String developmentTeamID;
    @CheckForNull
    private String ipaName;
    @CheckForNull
    private String ipaOutputDirectory;
    @CheckForNull
    private String ipaExportMethod;
    /**
     * @deprecated 2.0.7
     *
    @CheckForNull
    private Boolean manualSigning;
     */
    @CheckForNull
    private String signingMethod;
    @CheckForNull
    private ArrayList<ProvisioningProfile> provisioningProfiles;
    @CheckForNull
    private String xcodeName;
    @CheckForNull
    private Boolean uploadBitcode;
    @CheckForNull
    private Boolean uploadSymbols;
    @CheckForNull
    private Boolean compileBitcode;
    @CheckForNull
    private String thinning;
    @CheckForNull
    private Boolean embedOnDemandResourcesAssetPacksInBundle;
    @CheckForNull
    private String onDemandResourcesAssetPacksBaseURL;
    @CheckForNull
    private String appURL;
    @CheckForNull
    private String displayImageURL;
    @CheckForNull
    private String fullSizeImageURL;
    @CheckForNull
    private String assetPackManifestURL;
    /**
     * @since 2.0.5
     */
    @CheckForNull
    private Boolean stripSwiftSymbols;
    /**
     * @since 2.0.7
     */
    @CheckForNull
    private Boolean copyProvisioningProfile;
    /*
     * @since 2.0.13
     */
    @CheckForNull
    private String keychainId;

    @CheckForNull
    public String getXcodeProjectPath() {
	return xcodeProjectPath;
    }

    @DataBoundSetter
    public void setXcodeProjectPath(String xcodeProjectPath) {
	this.xcodeProjectPath = xcodeProjectPath;
    }

    @CheckForNull
    public String getXcodeProjectFile() {
	return xcodeProjectFile;
    }

    public Boolean getUnlockKeychain() {
	return unlockKeychain;
    }

    @DataBoundSetter
    public void setUnlockKeychain(Boolean unlockKeychain) {
	this.unlockKeychain = unlockKeychain;
    }

    @CheckForNull
    public String getKeychainName() {
	return keychainName;
    }

    @DataBoundSetter
    public void setKeychainName(String keychainName) {
	this.keychainName = keychainName;
    }

    @CheckForNull
    public String getKeychainPath() {
	return keychainPath;
    }

    @DataBoundSetter
    public void setKeychainPath(String keychainPath) {
	this.keychainPath = keychainPath;
    }

    @CheckForNull
    public Secret getKeychainPwd() {
	return keychainPwd;
    }

    @DataBoundSetter
    public void setKeychainPwd(Secret keychainPwd) {
	this.keychainPwd = keychainPwd;
    }

    @CheckForNull
    public String getSymRoot() {
	return symRoot;
    }

    @DataBoundSetter
    public void setSymRoot(String symRoot) {
	this.symRoot = symRoot;
    }

    @CheckForNull
    public String getXcodeWorkspaceFile() {
	return xcodeWorkspaceFile;
    }

    @DataBoundSetter
    public void setXcodeWorkspaceFile(String xcodeWorkspaceFile) {
	this.xcodeWorkspaceFile = xcodeWorkspaceFile;
    }

    @CheckForNull
    public String getXcodeSchema() {
	return xcodeSchema;
    }

    @DataBoundSetter
    public void setXcodeSchema(String xcodeSchema) {
	this.xcodeSchema = xcodeSchema;
    }

    @CheckForNull
    public String getArchiveDir() {
	return archiveDir;
    }

    @DataBoundSetter
    public void setArchiveDir(String archiveDir) {
	this.archiveDir = archiveDir;
    }

    @CheckForNull
    public String getDevelopmentTeamName() {
	return developmentTeamName;
    }

    @DataBoundSetter
    public void setDevelopmentTeamName(String developmentTeamName) {
	this.developmentTeamName = developmentTeamName;
    }

    @CheckForNull
    public String getDevelopmentTeamID() {
	return developmentTeamID;
    }

    @DataBoundSetter
    public void setDevelopmentTeamID(String developmentTeamID) {
	this.developmentTeamID = developmentTeamID;
    }

    @CheckForNull
    public String getIpaName() {
	return ipaName;
    }

    @DataBoundSetter
    public void setIpaName(String ipaName) {
	this.ipaName = ipaName;
    }

    @CheckForNull
    public String getIpaOutputDirectory() {
	return ipaOutputDirectory;
    }

    @DataBoundSetter
    public void setIpaOutputDirectory(String ipaOutputDirectory) {
	this.ipaOutputDirectory = ipaOutputDirectory;
    }

    @CheckForNull
    public String getIpaExportMethod() {
	return ipaExportMethod;
    }

    @DataBoundSetter
    public void setIpaExportMethod(String ipaExportMethod) {
	this.ipaExportMethod = ipaExportMethod;
    }

    @Deprecated
    public Boolean getManualSigning() {
	return ( signingMethod == null || signingMethod.equals("manual") );
    }

    @Deprecated
    @DataBoundSetter
    public void setManualSigning(Boolean manualSigning) {
	this.signingMethod = BooleanUtils.isTrue(manualSigning) ? "manual" : "automatic";
    }

    @CheckForNull
    public String getSigningMethod() {
	return signingMethod == null ? "automatic" : signingMethod;
    }

    @DataBoundSetter
    public void setSigningMethod(String signingMethod) {
	this.signingMethod = signingMethod;
    }

    @CheckForNull
    public ArrayList<ProvisioningProfile> getProvisioningProfiles() {
	return provisioningProfiles;
    }

    @DataBoundSetter
    public void setProvisioningProfiles(ArrayList<ProvisioningProfile> provisioningProfiles) {
	this.provisioningProfiles = provisioningProfiles;
    }

    @CheckForNull
    public String getXcodeName() {
	return xcodeName;
    }

    @DataBoundSetter
    public void setXcodeName(String xcodeName) {
	this.xcodeName = xcodeName;
    }

    public Boolean getUploadBitcode() {
	return uploadBitcode;
    }

    @DataBoundSetter
    public void setUploadBitcode(Boolean uploadBitcode) {
	this.uploadBitcode = uploadBitcode;
    }

    public Boolean getUploadSymbols() {
	return uploadSymbols;
    }

    @DataBoundSetter
    public void setUploadSymbols(Boolean uploadSymbols) {
	this.uploadSymbols = uploadSymbols;
    }

    public Boolean getCompileBitcode() {
	return compileBitcode;
    }

    @DataBoundSetter
    public void setCompileBitcode(Boolean compileBitcode) {
	this.compileBitcode = compileBitcode;
    }

    @CheckForNull
    public String getThinning() {
	return thinning;
    }

    @DataBoundSetter
    public void setThinning(String thinning) {
	this.thinning = thinning;
    }

    public Boolean getPackResourcesAsset() {
	return embedOnDemandResourcesAssetPacksInBundle;
    }

    @DataBoundSetter
    public void setPackResourcesAsset(Boolean packResourcesAsset) {
	this.embedOnDemandResourcesAssetPacksInBundle = packResourcesAsset;
    }

    @CheckForNull
    public String getResourcesAssetURL() {
	return onDemandResourcesAssetPacksBaseURL;
    }

    @DataBoundSetter
    public void setResourcesAssetURL(String resourcesAssetURL) {
	this.onDemandResourcesAssetPacksBaseURL = resourcesAssetURL;
    }

    @CheckForNull
    public String getAppURL() {
	return appURL;
    }

    @DataBoundSetter
    public void setAppURL(String appURL) {
	this.appURL = appURL;
    }

    @CheckForNull
    public String getDisplayImageURL() {
	return displayImageURL;
    }

    @DataBoundSetter
    public void setDisplayImageURL(String displayImageURL) {
	this.displayImageURL = displayImageURL;
    }

    @CheckForNull
    public String getFullSizeImageURL() {
	return fullSizeImageURL;
    }

    @DataBoundSetter
    public void setFullSizeImageURL(String fullSizeImageURL) {
	this.fullSizeImageURL = fullSizeImageURL;
    }

    @CheckForNull
    public String getAssetPackManifestURL() {
	return assetPackManifestURL;
    }

    @DataBoundSetter
    public void setAssetPackManifestURL(String assetPackManifestURL) {
	this.assetPackManifestURL = assetPackManifestURL;
    }

    public Boolean getStripSwiftSymbols() {
	return stripSwiftSymbols == null ? Boolean.valueOf(true) : stripSwiftSymbols;
    }

    @DataBoundSetter
    public void setStripSwiftSymbols(Boolean stripSwiftSymbols) {
	this.stripSwiftSymbols = stripSwiftSymbols;
    }

    public Boolean getCopyProvisioningProfile() {
	return copyProvisioningProfile == null ? Boolean.valueOf(true) : copyProvisioningProfile;
    }

    @DataBoundSetter
    public void setCopyProvisioningProfile(Boolean copyProvisioningProfile) {
	this.copyProvisioningProfile = copyProvisioningProfile;
    }

    @CheckForNull
    public String getKeychainId() {
	return keychainId;
    }

    @DataBoundSetter
    public void setKeychainId(String keychainId) {
	this.keychainId = keychainId;
    }

    @DataBoundConstructor
    public ExportIpa() {
    }

    @Deprecated
    public ExportIpa(String xcodeProjectPath, String xcodeProjectFile,
                Boolean unlockKeychain, String keychainName, String keychainPath, String keychainPwd, String symRoot, String xcodeWorkspaceFile,
                String xcodeSchema, String archiveDir, String developmentTeamName, String developmentTeamID,
                String ipaName, String ipaOutputDirectory,
                String ipaExportMethod,
                String signingMethod, ArrayList<ProvisioningProfile> provisioningProfiles, String xcodeName,
		Boolean uploadBitcode, Boolean uploadSymbols, Boolean compileBitcode, String thinning,
		Boolean packResourcesAsset, String resourcesAssetURL,
		String appURL, String displayImageURL, String fullSizeImageURL,
		String assetPackManifestURL) {
	this();
        this.xcodeProjectPath = xcodeProjectPath;
        this.xcodeProjectFile = xcodeProjectFile;
        this.keychainName = keychainName;
        this.xcodeWorkspaceFile = xcodeWorkspaceFile;
        this.xcodeSchema = xcodeSchema;
        this.developmentTeamName = developmentTeamName;
        this.developmentTeamID = developmentTeamID;
        this.unlockKeychain = unlockKeychain;
        this.keychainPath = keychainPath;
        this.keychainPwd = Secret.fromString(keychainPwd);
        this.symRoot = symRoot;
        this.archiveDir = archiveDir;
        this.ipaName = ipaName;
        this.ipaOutputDirectory = ipaOutputDirectory;
        this.ipaExportMethod = ipaExportMethod;
        this.signingMethod = signingMethod;
        this.provisioningProfiles = provisioningProfiles;
	this.xcodeName = xcodeName;
        this.uploadBitcode = uploadBitcode;
        this.uploadSymbols = uploadSymbols;
        this.compileBitcode = compileBitcode;
        this.thinning = thinning;
        this.embedOnDemandResourcesAssetPacksInBundle = packResourcesAsset;
        this.onDemandResourcesAssetPacksBaseURL = resourcesAssetURL;
        this.appURL = appURL;
        this.displayImageURL = displayImageURL;
        this.fullSizeImageURL = fullSizeImageURL;
        this.assetPackManifestURL = assetPackManifestURL;
	this.stripSwiftSymbols = true;
    }

    @Override
    public void perform(Run<?, ?> build, FilePath filePath, Launcher launcher, TaskListener listener) throws InterruptedException, IOException {
        _perform(build, filePath, launcher, build.getEnvironment(listener), listener);
    }

    @SuppressFBWarnings("DM_DEFAULT_ENCODING")
    private boolean _perform(Run<?,?> build, FilePath filePath, Launcher launcher, EnvVars envs, TaskListener listener) throws InterruptedException, IOException {
	XCodeBuilder builder = new XCodeBuilder(true, false, true, null, false, false, null,
                null, null, xcodeProjectPath, xcodeProjectFile, null,
                null, null, unlockKeychain,
                keychainName, keychainPath, Secret.toString(keychainPwd), symRoot, xcodeWorkspaceFile,
                xcodeSchema, archiveDir, developmentTeamName, developmentTeamID, false,
                ipaName, false, ipaOutputDirectory, false, null,
                null, false, ipaExportMethod, signingMethod, provisioningProfiles, xcodeName,
		uploadBitcode, uploadSymbols, compileBitcode, thinning,
		embedOnDemandResourcesAssetPacksInBundle, onDemandResourcesAssetPacksBaseURL,
		appURL, displayImageURL, fullSizeImageURL, assetPackManifestURL);
	builder.setStripSwiftSymbols(stripSwiftSymbols);
	builder.setCopyProvisioningProfile(copyProvisioningProfile);
		
	builder.setSkipBuildStep(true);
	builder.setKeychainId(keychainId);
	builder.perform(build, filePath, launcher, listener);
	return true;
    }

    public GlobalConfigurationImpl getGlobalConfiguration() {
        return getDescriptor().getGlobalConfiguration();
    }

    @Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl) super.getDescriptor();
    }

    @Extension
    @Symbol("exportIpa")
    public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
        GlobalConfigurationImpl globalConfiguration;

        @Override
        public String getDisplayName() {
            return Messages.ExportIpa_ExportIpa();
        }

        public DescriptorImpl() {
            load();
        }

        @SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
        @Inject
        void setGlobalConfiguration(GlobalConfigurationImpl c) {
            this.globalConfiguration = c;
        }

        public GlobalConfigurationImpl getGlobalConfiguration() {
            return globalConfiguration;
        }

        @Override
        public boolean isApplicable(Class<? extends AbstractProject> aClass) {
            return true;
        }

        public String getUUID() {
            return "" + UUID.randomUUID().getMostSignificantBits();
        }

	public FormValidation doCheckArchiveDir(@QueryParameter String value) {
	    if ( value.isEmpty() ) {
		return FormValidation.error(Messages.ExportIpa_NeedToSpecifyArchiveLocation());
	    }
	    return FormValidation.ok();
	}

        public FormValidation doCheckResourcesAssetURL(@QueryParameter String value, @QueryParameter Boolean packResourcesAsset) {
            if ( StringUtils.isEmpty(value) && !packResourcesAsset ) {
                return FormValidation.error(Messages.XCodeBuilder_NeedOnDemandResourcesURL());
            }
            return FormValidation.ok();
        }

	public FormValidation doCheckIpaExportMethod(@QueryParameter String value) {
	    if ( !ArrayUtils.contains(VALID_IPA_EXPORT_METHODS, value) ) {
		String validMethodsMsg = StringUtils.join(VALID_IPA_EXPORT_METHODS, ", ");
		return FormValidation.error(Messages.XCodeBuilder_IpaExportMethodMuestBeOneOfTheFollowing(validMethodsMsg));
	    }
	    return FormValidation.ok();
	}

	public FormValidation doCheckXcodeWorkspaceFile(@QueryParameter String value, @QueryParameter String xcodeSchema, @QueryParameter String target) {
	    if ( !StringUtils.isEmpty(value) ) {
		if ( !StringUtils.isEmpty(target) ) {
		    return FormValidation.error(Messages.XCodeBuilder_WorkspaceAndTargetCantSpecifySameTime());
		}
		if ( StringUtils.isEmpty(xcodeSchema) ) {
		    return FormValidation.error(Messages.XCodeBuilder_SpecifyWorkspaceAlsoSetScheme());
		}
	    }
	    return FormValidation.ok();
	}

	public FormValidation doCheckXcodeSchema(@QueryParameter String value,  @QueryParameter Boolean generateArchive, @QueryParameter String xcodeWorkspaceFile, @QueryParameter String target) {
	    if ( !StringUtils.isEmpty(value) ) {
		if ( !StringUtils.isEmpty(target) ) {
		    return FormValidation.error(Messages.XCodeBuilder_SchemeAndTargetCantSpecifySameTime());
		}
	    }
	    else {
		if ( !StringUtils.isEmpty(xcodeWorkspaceFile) ) {
		    return FormValidation.error(Messages.XCodeBuilder_SpecifyWorkspaceAlsoSetScheme());
		}
                return FormValidation.warning(Messages.XCodeBuilder_NeedSchema());
	    }
	    return FormValidation.ok();
	}
    }
}


================================================
FILE: src/main/java/au/com/rayh/GlobalConfigurationImpl.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2013 Maur�cio Hanika
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package au.com.rayh;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import hudson.Extension;
import hudson.model.AbstractProject;
import hudson.model.AutoCompletionCandidates;
import hudson.util.FormValidation;
import jenkins.model.GlobalConfiguration;

import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Logger;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import javax.servlet.ServletException;

/**
 * Stores global configuration for XCode.
 *
 * @since 1.4
 */
@Extension
public final class GlobalConfigurationImpl extends GlobalConfiguration {
    private static final Logger LOGGER = Logger.getLogger(GlobalConfigurationImpl.class.getName());
    @CheckForNull
    private String xcodebuildPath = "/usr/bin/xcodebuild";
    @CheckForNull
    private String xcrunPath = "/usr/bin/xcrun";
    @CheckForNull
    private String agvtoolPath = "/usr/bin/agvtool";
    // No one uses defaultKeychain.
    @Deprecated
    @CheckForNull
    private String defaultKeychain = "";
    @Deprecated
    @CheckForNull
    private ArrayList<Keychain> keychains = new ArrayList<>();
    @Deprecated
    @CheckForNull
    private ArrayList<Team> teams = new ArrayList<>();

    @DataBoundSetter
    public void setXcodebuildPath(String xcodebuildPath) {
        this.xcodebuildPath = xcodebuildPath;
    }

    @CheckForNull
    public String getXcodebuildPath() {
        return xcodebuildPath;
    }

    @DataBoundSetter
    public void setXcrunPath(String xcrunPath) {
        this.xcrunPath = xcrunPath;
    }

    @CheckForNull
    public String getXcrunPath() {
        return xcrunPath;
    }

    @DataBoundSetter
    public void setAgvtoolPath(String agvtoolPath) {
        this.agvtoolPath = agvtoolPath;
    }

    @CheckForNull
    public String getAgvtoolPath() {
        return agvtoolPath;
    }

    @Deprecated
    @DataBoundSetter
    public void setDefaultKeychain(String defaultKeychain) {
        this.defaultKeychain = defaultKeychain;
    }

    @Deprecated
    @CheckForNull
    public String getDefaultKeychain() {
        return defaultKeychain;
    }

    @Deprecated
    @DataBoundSetter
    public void setKeychains(ArrayList<Keychain> keychains) {
        this.keychains = keychains;
    }

    @Deprecated
    public ArrayList<Keychain> getKeychains() {
	return keychains == null ? keychains : new ArrayList<Keychain>();
    }

    @Deprecated
    @DataBoundSetter
    public void setTeams(ArrayList<Team> teams) {
        this.teams = teams;
    }

    @Deprecated
    public ArrayList<Team> getTeams() {
        return teams;
    }

    @DataBoundConstructor
    public GlobalConfigurationImpl() {
        super();
        load();
	LOGGER.fine("[Xcode] Default constructor: " + getKeychains().size());
    }

    @Deprecated
    public GlobalConfigurationImpl(String xcodebuildPath, String xcrunPath, String agvtoolPath, String defaultKeychain, ArrayList<Keychain> keychains, ArrayList<Team> teams) {
        this();

        this.setXcodebuildPath(xcodebuildPath);
        this.setXcrunPath(xcrunPath);
        this.setAgvtoolPath(agvtoolPath);
        this.setDefaultKeychain(defaultKeychain);
        this.setKeychains(keychains);
        this.setTeams(teams);

        LOGGER.fine("[Xcode] DataBoundConstructor: keychains.size " + keychains.size());
        if(teams != null) {
            LOGGER.fine("[Xcode] DataBoundConstructor: teams.size " + teams.size());
        }
    }

    @Deprecated
    public GlobalConfigurationImpl(String xcodebuildPath, String xcrunPath, String agvtoolPath, String defaultKeychain, ArrayList<Keychain> keychains) {
        this(xcodebuildPath, xcrunPath, agvtoolPath, defaultKeychain, keychains, null);
    }

    public FormValidation doCheckXcodebuildPath(@QueryParameter String value) throws IOException, ServletException {
        if (StringUtils.isEmpty(value)) {
            return FormValidation.error(Messages.XCodeBuilder_xcodebuildPathNotSet());
        } else {
            // TODO: check that the file exists (and if an agent is used ?)
        }
        return FormValidation.ok();
    }

    public FormValidation doCheckAgvtoolPath(@QueryParameter String value) throws IOException, ServletException {
        if (StringUtils.isEmpty(value)) {
            return FormValidation.error(Messages.XCodeBuilder_agvtoolPathNotSet());
        } else {
            // TODO: check that the file exists (and if an agent is used ?)
        }
        return FormValidation.ok();
    }

    public FormValidation doCheckXcrunPath(@QueryParameter String value) throws IOException, ServletException {
        if (StringUtils.isEmpty(value)) {
            return FormValidation.error(Messages.XCodeBuilder_xcrunPathNotSet());
        } else {
            // TODO: check that the file exists (and if an agent is used ?)
        }
        return FormValidation.ok();
    }

    /* Useless method that doesn't make sense.
    public FormValidation doCheckDefaultKeychain(@QueryParameter String value) throws IOException, ServletException {
        if (!StringUtils.isEmpty(value)) {
            Boolean foundKeychain = false;
            for (Keychain k : getKeychains()) {
                if (k.getKeychainName().equals(value)) {
                    foundKeychain = true;
                    break;
                }
            }

            if (!foundKeychain) {
                return FormValidation.error(Messages.OSXKeychainBuildWrapper_invalidDefaultKeychainName(value));
            }
        }

        return FormValidation.ok();
    }
     */

    public AutoCompletionCandidates doAutoCompleteDefaultKeychain(@QueryParameter String value) {
        AutoCompletionCandidates c = new AutoCompletionCandidates();
        for (Keychain keychain : getKeychains()) {
            if (keychain.getKeychainName().toLowerCase().startsWith(value.toLowerCase())) {
                c.add(keychain.getKeychainName());
            }
        }
        return c;
    }

    public boolean isApplicable(Class<? extends AbstractProject> aClass) {
        // indicates that this builder can be used with all kinds of project types
        return true;
    }

    @Override
    public String getDisplayName() {
        return Messages.XCodeBuilder_xcode();
    }

    @Override
    public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
        req.bindJSON(this, formData);
        setKeychains(new ArrayList<>(req.bindParametersToList(Keychain.class, "keychain.")));
        setTeams(new ArrayList<>(req.bindParametersToList(Team.class, "team.")));
        save();

        return super.configure(req, formData);
    }
}


================================================
FILE: src/main/java/au/com/rayh/InfoPlist.java
================================================
package au.com.rayh;

import hudson.FilePath;

//import org.kohsuke.stapler.DataBoundConstructor;

public class InfoPlist {

    private FilePath infoPlistFile;
    private String cfBundleIdentifier;
    private String cfBundleVersion;
    private String cfBundleShortVersionString;

    InfoPlist() {
	infoPlistFile = null;
	cfBundleIdentifier = null;
	cfBundleVersion = null;
	cfBundleShortVersionString = null;
    }

    //@DataBoundConstructor
    InfoPlist(FilePath infoPlistFile, String cfBundleIdentifier, String cfBundleVersion, String cfBundleShortVersionString) {
        this.infoPlistFile = infoPlistFile;
        this.cfBundleIdentifier = cfBundleIdentifier;
        this.cfBundleVersion = cfBundleVersion;
        this.cfBundleShortVersionString = cfBundleShortVersionString;
    }

    public FilePath getInfoPlistFile() {
        return this.infoPlistFile;
    }

    public void setInfoPlistFile(FilePath infoPlistFile) {
        this.infoPlistFile = infoPlistFile;
    }

    public String getCfBundleIdentifier() {
        return this.cfBundleIdentifier;
    }

    public void setCfBundleIdentifier(String cfBundleIdentifier) {
        this.cfBundleIdentifier = cfBundleIdentifier;
    }

    public String getCfBundleVersion() {
        return this.cfBundleVersion;
    }

    public void setCfBundleVersion(String cfBundleVersion) {
        this.cfBundleVersion = cfBundleVersion;
    }

    public String getCfBundleShortVersionString() {
        return this.cfBundleShortVersionString;
    }

    public void setCfBundleShortVersionString(String cfBundleShortVersionString) {
        this.cfBundleShortVersionString = cfBundleShortVersionString;
    }
}


================================================
FILE: src/main/java/au/com/rayh/JenkinsXCodeBuildOutputParser.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2011 Ray Yamamoto Hilton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package au.com.rayh;

import hudson.FilePath;
import hudson.Functions;
import hudson.model.TaskListener;

import java.io.BufferedOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;

import org.apache.commons.lang.StringUtils;

/**
 *
 * @author ray
 */
public class JenkinsXCodeBuildOutputParser extends XCodeBuildOutputParser {
    protected TaskListener buildListener;
    private FilePath testReportsDir;
    private OutputStream logFileOutputStream;
    private boolean ignoreTestResults;

	public JenkinsXCodeBuildOutputParser(FilePath workspace, TaskListener buildListener) throws IOException, InterruptedException {
		super();
        this.buildListener = buildListener;
        this.captureOutputStream = new LineBasedFilterOutputStream();
        this.consoleLog = true;
        this.logFileOutputStream = null;
	this.ignoreTestResults = false;

        testReportsDir = workspace.child("test-reports");
        testReportsDir.mkdirs();
    }

    public void setConsoleLog(boolean consoleLog) {
        this.consoleLog = consoleLog;
    }

    public void setIgnoreTestResults(boolean ignoreTestResults) {
	this.ignoreTestResults = ignoreTestResults;
    }
    
    public void setLogfilePath(final FilePath buildDirectory, final String logfileOutputDirectory) throws IOException, InterruptedException {
	// Remove buildDirectory.exists() && buildDirectory.isDirectory() from condition.
	// Because If Generate archive is not specified, directory was not created.
        if(!StringUtils.isEmpty(logfileOutputDirectory)) {
	    // Fix not to use timestamp for log file name. (Use "xcodebuild.log" as a fixed file name)
	    // Because using a timestamp as a filename, No way to know it with a script etc.
            FilePath logFilePath = buildDirectory.child(logfileOutputDirectory);
            // clean Directory
            if(logFilePath.exists()) {
                logFilePath.deleteRecursive();
            }
            // Create if non-existent
            if (!logFilePath.exists()) {
                logFilePath.mkdirs();
            }
            logFileOutputStream = new BufferedOutputStream(logFilePath.child("xcodebuild.log").write(),1024*512);
        }
    }
    
    public void closeLogfile() throws IOException {
    	if(logFileOutputStream != null) {
            logFileOutputStream.flush();
            logFileOutputStream.close();
            logFileOutputStream = null;
        }
    }

    public class LineBasedFilterOutputStream extends FilterOutputStream {
        StringBuilder buffer = new StringBuilder();

        public LineBasedFilterOutputStream() {
            super(buildListener.getLogger());
        }

        @Override
        public void write(int b) throws IOException {
	    if ( !ignoreTestResults ) {
                if((char)b == '\n') {
                    try {
                        handleLine(buffer.toString());
                        buffer = new StringBuilder();
                    } catch(Exception e) {  // Very fugly
                        Functions.printStackTrace(e, buildListener.fatalError(e.getMessage()));
                        throw new IOException(e);
                    }
                } else {
                    buffer.append((char)b);
                }
	    }
            if(consoleLog) {
                super.write(b);
            }
            if(logFileOutputStream != null) {
                logFileOutputStream.write(b);
            }
        }
        
        @Override
        public void close() throws IOException {
            if(logFileOutputStream != null) {
                logFileOutputStream.flush();
                logFileOutputStream.close();
                logFileOutputStream = null;
            }
            super.close();
        }
    }

	@Override
	protected OutputStream outputForSuite() throws IOException,
			InterruptedException {
		return testReportsDir.child("TEST-" + currentTestSuite.getName() + ".xml").write();
	}
}


================================================
FILE: src/main/java/au/com/rayh/Keychain.java
================================================
package au.com.rayh;

import hudson.util.Secret;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

public class Keychain {
    private String keychainName;
    private String keychainPath;
    private Secret keychainPassword;
    private Boolean inSearchPath;

    public Keychain() {
    }

    @Deprecated
    @DataBoundConstructor
    public Keychain(String keychainName, String keychainPath, String keychainPassword, Boolean inSearchPath) {
        this.keychainName = keychainName;
        this.keychainPath = keychainPath;
        this.keychainPassword = Secret.fromString(keychainPassword);
        this.inSearchPath = inSearchPath;
    }

    public String getKeychainName() {
        return keychainName;
    }

    @DataBoundSetter
    public void setKeychainName(String keychainName) {
        this.keychainName = keychainName;
    }

    public String getKeychainPath() {
        return keychainPath;
    }

    @DataBoundSetter
    public void setKeychainPath(String keychainPath) {
        this.keychainPath = keychainPath;
    }

    public Secret getKeychainPassword() {
        return keychainPassword;
    }

    @DataBoundSetter
    public void setKeychainPassword(Secret keychainPassword) {
        this.keychainPassword = keychainPassword;
    }

    public Boolean isInSearchPath() {
        return inSearchPath;
    }

    @DataBoundSetter
    public void setInSearchPath(Boolean inSearchPath) {
        this.inSearchPath = inSearchPath;
    }
}


================================================
FILE: src/main/java/au/com/rayh/KeychainPasswordAndPath.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2011-2012, CloudBees, Inc., Stephen Connolly.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package au.com.rayh;

import com.cloudbees.plugins.credentials.CredentialsNameProvider;
import com.cloudbees.plugins.credentials.NameWith;
import com.cloudbees.plugins.credentials.common.PasswordCredentials;
import com.cloudbees.plugins.credentials.common.StandardCredentials;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Util;
import hudson.util.Secret;

import java.io.IOException;

/**
 * Credentials that have an ID, description and macOS Keychain password and path.
 *
 */
@NameWith(value = KeychainPasswordAndPath.NameProvider.class, priority = 32)
public interface KeychainPasswordAndPath extends StandardCredentials, PasswordCredentials {
    /**
     *
     *
     */
    Secret getPassword();
    String getKeychainPath();
    boolean isInSearchPath();
    String getInSearchPath();

    /**
     * Our name provider.
     *
     * @since 2.0.12
     */
    public static class NameProvider extends CredentialsNameProvider<KeychainPasswordAndPath> {

        /**
         * {@inheritDoc}
         */
        @NonNull
        @Override
        public String getName(@NonNull KeychainPasswordAndPath c) {
            String description = Util.fixEmptyAndTrim(c.getDescription());
            return c.getKeychainPath() + (description != null ? " (" + description + ")" : "");
        }
    }
}


================================================
FILE: src/main/java/au/com/rayh/KeychainPasswordAndPathBinding.java
================================================
/*
 * The MIT License
 *
 *  Copyright (c) 2016, CloudBees, Inc.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 *
 */

package au.com.rayh;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.Run;
import hudson.model.TaskListener;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.credentialsbinding.BindingDescriptor;
import org.jenkinsci.plugins.credentialsbinding.MultiBinding;
import org.kohsuke.stapler.DataBoundConstructor;

import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author <a href="mailto:kazuhide.t@linux-powered.com">Kazuhide Takahashi</a>
 */
public class KeychainPasswordAndPathBinding extends MultiBinding<KeychainPasswordAndPath> {

    public final static String DEFAULT_KEYCHAIN_PATH_VARIABLE_NAME = "KEYCHAIN_PATH";
    private final static String DEFAULT_PASSWORD_VARIABLE_NAME = "PASSWORD";
    private final static String DEFAULT_IN_SEARCH_PATH_VARIABLE_NAME = "IN_SEARCH_PATH";

    @NonNull
    private final String keychainPathVariable;
    @NonNull
    private final String passwordVariable;
    @NonNull
    private final String inSearchPathVariable;

    /**
     *
     * @param keychainPathVariable if {@code null}, {@value DEFAULT_KEYCHAIN_PATH_VARIABLE_NAME} will be used.
     * @param passwordVariable if {@code null}, {@value DEFAULT_PASSWORD_VARIABLE_NAME} will be used.
     * @param inSearchPathVariable if {@code null}, {@value DEFAULT_IN_SEARCH_PATH_VARIABLE_NAME} will be used.
     * @param credentialsId identifier which should be referenced when accessing the credentials from a job/pipeline.
     */
    @DataBoundConstructor
    public KeychainPasswordAndPathBinding(@Nullable String keychainPathVariable, @Nullable String passwordVariable, @Nullable String inSearchPathVariable, String credentialsId) {
        super(credentialsId);
        this.keychainPathVariable = StringUtils.defaultIfBlank(keychainPathVariable, DEFAULT_KEYCHAIN_PATH_VARIABLE_NAME);
        this.passwordVariable = StringUtils.defaultIfBlank(passwordVariable, DEFAULT_PASSWORD_VARIABLE_NAME);
        this.inSearchPathVariable = StringUtils.defaultIfBlank(inSearchPathVariable, DEFAULT_IN_SEARCH_PATH_VARIABLE_NAME);
    }

    @NonNull
    public String getKeychainPathVariable() {
        return keychainPathVariable;
    }

    @NonNull
    public String getPasswordVariable() {
        return passwordVariable;
    }

    @NonNull
    public String getInSearchPathVariable() {
        return inSearchPathVariable;
    }

    @Override
    protected Class<KeychainPasswordAndPath> type() {
        return KeychainPasswordAndPath.class;
    }

    @Override
    public MultiEnvironment bind(@NonNull Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener) throws IOException, InterruptedException {
        KeychainPasswordAndPath credential = getCredentials(build);
        Map<String,String> m = new HashMap<String,String>();
        m.put(keychainPathVariable, credential.getKeychainPath());
        m.put(passwordVariable, credential.getPassword().getPlainText());
        m.put(inSearchPathVariable, credential.getInSearchPath());
        return new MultiEnvironment(m);
    }

    @Override
    public Set<String> variables() {
        return new HashSet<String>(Arrays.asList(keychainPathVariable, passwordVariable, inSearchPathVariable));
    }

    @Extension
    public static class DescriptorImpl extends BindingDescriptor<KeychainPasswordAndPath> {

        @Override protected Class<KeychainPasswordAndPath> type() {
            return KeychainPasswordAndPath.class;
        }

        @Override public String getDisplayName() {
            return Messages.KeychainPasswordAndPath_DisplayName();
        }
    }

}


================================================
FILE: src/main/java/au/com/rayh/KeychainPasswordAndPathImpl.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2011-2016, CloudBees, Inc., Stephen Connolly.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package au.com.rayh;

import com.cloudbees.plugins.credentials.CredentialsDescriptor;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.Util;
import hudson.security.ACL;
import hudson.util.Secret;
import org.kohsuke.stapler.DataBoundConstructor;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;
import org.kohsuke.stapler.DataBoundSetter;

import java.util.Collections;
import java.util.List;

/**
 *
 */
@SuppressWarnings("unused") // read resolved by extension plugins
public class KeychainPasswordAndPathImpl extends BaseStandardCredentials implements KeychainPasswordAndPath {

    /**
     * The Keychain path.
     */
    @NonNull
    private String keychainPath;

    /**
     * The password.
     */
    @NonNull
    private Secret password;

    /**
     * The flag for keychain in search path.
     */
    private String inSearchPath;

    /**
     * Constructor.
     *
     * @param scope           the credentials scope
     * @param id              the ID or {@code null} to generate a new one.
     * @param description     the description.
     * @param keychainPath    the Keychain path.
     * @param password        the password.
     * @param inSearchPath    flag for keychain in search path.
     */
    @DataBoundConstructor
    @SuppressWarnings("unused") // by stapler
    public KeychainPasswordAndPathImpl(@CheckForNull CredentialsScope scope,
                                       @CheckForNull String id,
                                       @CheckForNull String description,
                                       @CheckForNull String keychainPath,
                                       @CheckForNull String password,
                                       @CheckForNull String inSearchPath) {
        super(scope, id, description);
        this.keychainPath = Util.fixNull(keychainPath);
        this.password = Secret.fromString(password);
        this.inSearchPath = inSearchPath;
    }

    /**
     * {@inheritDoc}
     */
    public Secret getPassword() {
        return password;
    }

    @DataBoundSetter
    public void setPassword(Secret password) {
        this.password = password;
    }

    /**
     * macOS Keychain path.
     * @return full path for macOS keychain
     */
    @NonNull
    public String getKeychainPath() {
        return keychainPath;
    }

    @DataBoundSetter
    public void setKeychainPath(String keychainPath) {
        this.keychainPath = keychainPath;
    }

    /**
     * Add keychain to search path.
     * @return inSearchPath by String.
     */
    public String getInSearchPath() {
        return inSearchPath;
    }

    @DataBoundSetter
    public void setInSearchPath(String inSearchPath) {
        this.inSearchPath = inSearchPath;
    }

    /**
     * Add keyc hain to search path.
     * @return check is inSearchPath equals "true".
     */
    public boolean isInSearchPath() {
        return inSearchPath == null ? false : inSearchPath.equals("true");
    }

    /**
     * {@inheritDoc}
     */
    @Extension
    public static class DescriptorImpl extends BaseStandardCredentialsDescriptor {

        /**
         * {@inheritDoc}
         */
        @Override
        public String getDisplayName() {
            return Messages.KeychainPasswordAndPath_DisplayName();
        }

        /*
         * {@inheritDoc}
         *
        @Override
        public String getIconClassName() {
            return "icon-credentials";
        }
        */
    }

    public static List<KeychainPasswordAndPathImpl> getAllKeycainInfo() {
        return CredentialsProvider.lookupCredentials(KeychainPasswordAndPathImpl.class, (hudson.model.Item)null, ACL.SYSTEM, Collections.<DomainRequirement>emptyList());
    }

}


================================================
FILE: src/main/java/au/com/rayh/KeychainUnlockStep.java
================================================
package au.com.rayh;

import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.*;
import hudson.security.ACL;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.ArgumentListBuilder;
import hudson.util.FormValidation;
import hudson.util.Secret;

import jenkins.tasks.SimpleBuildStep;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import javax.inject.Inject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.UUID;

/**
 * Installs {@link DeveloperProfile} into the current slave and unlocks its keychain
 * in preparation for the signing that uses it.
 *
 * TODO: destroy identity in the end.
 *
 * @author Kohsuke Kawaguchi
 */
@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
public class KeychainUnlockStep extends Builder implements SimpleBuildStep {
    @Deprecated
    @CheckForNull
    private String keychainName;
    @CheckForNull
    private String keychainId;
    @CheckForNull
    private String keychainPath;
    @CheckForNull
    private Secret keychainPwd;

    @Deprecated
    @CheckForNull
    public String getKeychainName() {
        return keychainName;
    }

    @CheckForNull
    public String getKeychainId() {
        return keychainId;
    }

    @Deprecated
    @DataBoundSetter
    public void setKeychainName(String keychainName) {
        this.keychainName = keychainName;
    }

    @DataBoundSetter
    public void setKeychainId(String keychainId) {
        this.keychainId = keychainId;
    }

    @CheckForNull
    public String getKeychainPath() {
        return keychainPath;
    }

    @DataBoundSetter
    public void setKeychainPath(String keychainPath) {
        this.keychainPath = keychainPath;
    }

    @CheckForNull
    public Secret getKeychainPwd() {
        return keychainPwd;
    }

    @DataBoundSetter
    public void setKeychainPwd(Secret keychainPwd) {
        this.keychainPwd = keychainPwd;
    }

    @DataBoundConstructor
    public KeychainUnlockStep() {
    }

    @Deprecated
    public KeychainUnlockStep(String keychainName) {
	this();
	this.keychainName = keychainName;
    }

    @Override
    public void perform(@NonNull Run<?, ?> run, @NonNull FilePath workspace, @NonNull Launcher launcher, @NonNull TaskListener listener) throws InterruptedException, IOException {
	EnvVars envs = run.getEnvironment(listener);
	String _keychainId = envs.expand(this.keychainId);
        String _keychainName = envs.expand(this.keychainName);

        String _keychainPath;
        String _keychainPwd;
        if ( StringUtils.isNotEmpty(_keychainName) ) {
            // for backward compatibility
            listener.getLogger().println(Messages.XCodeBuilder_UseDeprecatedKeychainInfo());
            Keychain keychain = getKeychain(_keychainName);
            if ( keychain == null ) {
                throw new AbortException(Messages.DeveloperProfileLoader_NoKeychainInfoConfigured());
            }
            else {
                _keychainPath = envs.expand(keychain.getKeychainPath());
                _keychainPwd = envs.expand(Secret.toString(keychain.getKeychainPassword()));
            }
        }
        else if ( StringUtils.isNotEmpty(_keychainId) ) {
            // for backward compatibility
            KeychainPasswordAndPath keychain = getKeychainPasswordAndPath(run.getParent(), _keychainId);
            if ( keychain == null ) {
                throw new AbortException(Messages.DeveloperProfileLoader_NoKeychainInfoConfigured());
            }
            else {
                _keychainPath = envs.expand(keychain.getKeychainPath());
                _keychainPwd = envs.expand(keychain.getPassword().getPlainText());
            }
        }
        else {
            _keychainPath = envs.expand(this.keychainPath);
            _keychainPwd = envs.expand(Secret.toString(this.keychainPwd));
        }

        ArgumentListBuilder args;

        args = new ArgumentListBuilder("security", "unlock-keychain");
        args.add("-p").addMasked(_keychainPwd);
        args.add(_keychainPath);
        invoke(launcher, listener, args, "Failed to unlock keychain");
    }

    @Override
    public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
        perform(build, build.getWorkspace(), launcher, listener);

        return true;
    }

    @Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl) super.getDescriptor();
    }

    public GlobalConfigurationImpl getGlobalConfiguration() {
        return getDescriptor().getGlobalConfiguration();
    }

    public Keychain getKeychain(String keychainName) {
        if ( !StringUtils.isEmpty(keychainName) ) {
            for ( Keychain keychain : getGlobalConfiguration().getKeychains() ) {
                if ( keychain.getKeychainName().equals(keychainName) )
                    return keychain;
            }
        }

        if ( !StringUtils.isEmpty(this.keychainPath) ) {
            Keychain newKeychain = new Keychain();
            newKeychain.setKeychainPath(keychainPath);
            newKeychain.setKeychainPassword(this.keychainPwd);
            return newKeychain;
        }

        return null;
    }

    public KeychainPasswordAndPath getKeychainPasswordAndPath(Item context, String keychainId) {
        return (KeychainPasswordAndPath) CredentialsMatchers.firstOrNull(
                CredentialsProvider.lookupCredentials(KeychainPasswordAndPath.class, context,
                        ACL.SYSTEM, Collections.EMPTY_LIST),
                CredentialsMatchers.withId(keychainId));
    }

    private ByteArrayOutputStream invoke(Launcher launcher, TaskListener listener, ArgumentListBuilder args, String errorMessage) throws IOException, InterruptedException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        if (launcher.launch().cmds(args).stdout(output).join()!=0) {
            listener.getLogger().write(output.toByteArray());
            throw new AbortException(errorMessage);
        }
        return output;
    }

    @Extension
    @Symbol("unlockMacOSKeychain")
    public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
	GlobalConfigurationImpl globalConfiguration;

        @SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
        @Inject
        void setGlobalConfiguration(GlobalConfigurationImpl c) {
            this.globalConfiguration = c;
	}

        @Override
        public boolean isApplicable(Class<? extends AbstractProject> jobType) {
            return true;
        }

        @Override
        public String getDisplayName() {
            return Messages.OSXKeychainUnclockStep_DisplayName();
        }

        public GlobalConfigurationImpl getGlobalConfiguration() {
            return globalConfiguration;
        }

        public String getUUID() {
            return "" + UUID.randomUUID().getMostSignificantBits();
        }

        public FormValidation doCheckKeychainPath(@QueryParameter String value, @QueryParameter String keychainName) {
            if ( StringUtils.isEmpty(keychainName) && StringUtils.isEmpty(value) ) {
                return FormValidation.error(Messages.DeveloperProfileLoader_MustSpecifyKeychainPath());
            }
            return FormValidation.ok();
        }

        public FormValidation doCheckKeychainPwd(@QueryParameter Secret value, @QueryParameter String keychainName) {
            if ( StringUtils.isEmpty(keychainName) && StringUtils.isEmpty(Secret.toString(value)) ) {
                return FormValidation.error(Messages.DeveloperProfileLoader_MustSpecifyKeychainPwd());
            }
            return FormValidation.ok();
        }
    }
}


================================================
FILE: src/main/java/au/com/rayh/MobileProvisionParser.java
================================================
package au.com.rayh;

import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;


/**
 * Created by ud10404 on 5/9/14.
 */
public class MobileProvisionParser {

    private List<String> targets = new ArrayList<>();
    private List<String> configurations = new ArrayList<>();
    private List<String> schemes = new ArrayList<>();

    public MobileProvisionParser(String xcodebuildListOutput) {

        if(xcodebuildListOutput == null) {
            return;
        }

        String [] lines = xcodebuildListOutput.split("\n");
        List<String> curList = null;
        for(String line : lines) {
            line = line.trim();
            if (StringUtils.isEmpty(line)) {
                curList = null;
            } else if("Targets:".equals(line)) {
                curList = targets;
            } else if("Build Configurations:".equals(line)) {
                curList = configurations;
            } else if("Schemes:".equals(line)) {
                curList = schemes;
            } else if(curList != null) {
                curList.add(line);
            }
        }
    }

    public List<String> getTargets() {
        return this.targets;
    }

    public List<String> getConfigurations() {
        return this.configurations;
    }

    public List<String> getSchemes() {
        return this.schemes;
    }
}


================================================
FILE: src/main/java/au/com/rayh/ProjectScheme.java
================================================
package au.com.rayh;

public class ProjectScheme {
    //public String parallelizeBuildables;
    //public String buildImplicitDependencies;
    //public String blueprintIdentifier;
    //public String buildForTesting;
    //public String buildForRunning;
    //public String buildForProfiling;
    //public String buildForArchiving;
    //public String buildForAnalyzing;
    //public String buildableIdentifier;
    //public String buildableName;
    public String blueprintName;
    public String referencedContainer;

    ProjectScheme() {
	//parallelizeBuildables = null;
	//buildImplicitDependencies = null;
	//blueprintIdentifier = null;
	//buildForTesting = null;
	//buildForRunning = null;
	//buildForProfiling = null;
	//buildForArchiving = null;
	//buildForAnalyzing = null;
	//buildableIdentifier = null;
	//buildableName = null;
	blueprintName = null;
	referencedContainer = null;
    }
}


================================================
FILE: src/main/java/au/com/rayh/ProjectTarget.java
================================================
package au.com.rayh;

import java.util.HashMap;

public class ProjectTarget {
    public String uuid;
    //public String name;
    public String productType;
    public String provisioningStyle;
    public String testTargetID;
    public String defaultConfigurationName;
    public HashMap<String, BuildConfiguration> buildConfiguration;

    ProjectTarget() {
	uuid = null;
	//name = null;
	productType = null;
	provisioningStyle = null;
        testTargetID = null;
	defaultConfigurationName = null;
	
	buildConfiguration = new HashMap<String, BuildConfiguration>();
    }
}



================================================
FILE: src/main/java/au/com/rayh/ProvisioningProfile.java
================================================
package au.com.rayh;

import org.kohsuke.stapler.DataBoundConstructor;
import hudson.EnvVars;

public class ProvisioningProfile {

    private static final String PLIST_FORMAT = "<key>${APP_ID}</key><string>${UUID}</string>";

    private String provisioningProfileAppId;
    private String provisioningProfileUUID;

    public ProvisioningProfile() {
    }

    @DataBoundConstructor
    public ProvisioningProfile(String provisioningProfileAppId, String provisioningProfileUUID) {
        this.provisioningProfileAppId = provisioningProfileAppId;
        this.provisioningProfileUUID = provisioningProfileUUID;
    }

    public String getProvisioningProfileAppId() {
        return provisioningProfileAppId;
    }

    public void setProvisioningProfileAppId(String provisioningProfileAppId) {
        this.provisioningProfileAppId = provisioningProfileAppId;
    }

    public String getProvisioningProfileUUID() {
        return provisioningProfileUUID;
    }

    public void setProvisioningProfileUUID(String provisioningProfileUUID) {
        this.provisioningProfileUUID = provisioningProfileUUID;
    }

    public String toPlist(EnvVars envs) {
        return PLIST_FORMAT.replace("${APP_ID}", envs.expand(provisioningProfileAppId))
                .replace("${UUID}", envs.expand(provisioningProfileUUID));
    }
}


================================================
FILE: src/main/java/au/com/rayh/Team.java
================================================
package au.com.rayh;

import org.kohsuke.stapler.DataBoundConstructor;

public class Team {

    private String teamName;
    private String teamID;

    public Team() {
    }

    @DataBoundConstructor
    public Team(String teamName, String teamID) {
        this.teamName = teamName;
        this.teamID = teamID;
    }

    public String getTeamName() {
        return teamName;
    }

    public void setTeamName(String teamName) {
        this.teamName = teamName;
    }

    public String getTeamID() {
        return teamID;
    }

    public void setTeamID(String teamID) {
        this.teamID = teamID;
    }
    
}


================================================
FILE: src/main/java/au/com/rayh/XCArchiveFileFilter.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2011 Ray Yamamoto Hilton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package au.com.rayh;

import java.io.File;
import java.io.FileFilter;
import java.io.Serializable;

/**
 * @author lampietti
 */
public class XCArchiveFileFilter implements FileFilter, Serializable {

    public boolean accept(File pathname) {
        return pathname.isDirectory() && pathname.getName().endsWith(".xcarchive");
    }
}


================================================
FILE: src/main/java/au/com/rayh/XCodeAction.java
================================================
package au.com.rayh;

import hudson.model.InvisibleAction;
import org.kohsuke.stapler.DataBoundConstructor;

/**
 * Simple Action for storing the build number
 * @author Reuben Bijl
 */
public class XCodeAction extends InvisibleAction {
    private String buildDescription;

    @DataBoundConstructor
    public XCodeAction(String buildDescription) {
        this.buildDescription = buildDescription;
    }

    public  String getBuildDescription() { return buildDescription; }
}

================================================
FILE: src/main/java/au/com/rayh/XCodeBuildNumberTokenMacro.java
================================================
package au.com.rayh;

import hudson.Extension;
import hudson.model.AbstractBuild;
import hudson.model.TaskListener;
import org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro;
import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;

import java.io.IOException;


@Extension
public class XCodeBuildNumberTokenMacro extends DataBoundTokenMacro {
    @Override
    public String evaluate(AbstractBuild<?, ?> context, TaskListener listener, String macroName)
            throws MacroEvaluationException, IOException, InterruptedException {
            XCodeAction a = context.getAction(XCodeAction.class);
            if(a == null){
                return "";
            }
			return a.getBuildDescription();
    }

    @Override
    public boolean acceptsMacroName(String macroName) {
        return macroName.equals("XCODE_BUILD_NUMBER");
    }
}

================================================
FILE: src/main/java/au/com/rayh/XCodeBuildOutputParser.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2011 Ray Yamamoto Hilton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package au.com.rayh;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import au.com.rayh.report.TestCase;
import au.com.rayh.report.TestError;
import au.com.rayh.report.TestFailure;
import au.com.rayh.report.TestSuite;

/**
 * Parse Xcode output and transform into JUnit-style xml test result files.
 * This utility class creates and manages a FilterOutputStream to parse the Xcode output to capture the
 * results of ocunit tests. 
 * @author John Bito &lt;jwbito@gmail.com&gt;
 */

public class XCodeBuildOutputParser {

    private static DateFormat[] dateFormats = {
	new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"),
	new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    };
    private static Pattern START_SUITE = Pattern.compile("Test Suite '([^\\/](?:\\.|[^'\\\\])*)'\\s+started at\\s+(.*)");
    private static Pattern END_SUITE = Pattern.compile("Test Suite '([^\\/](?:\\.|[^'\\\\])*)'\\s+\\S+\\s+at\\s+(.*).");
    private static Pattern START_TESTCASE = Pattern.compile("Test Case '-\\[(\\S+)\\s+(\\S+)\\]' started.");
    private static Pattern END_TESTCASE = Pattern.compile("Test Case '-\\[(\\S+)\\s+(\\S+)\\]' passed \\((.*) seconds\\).");
    private static Pattern ERROR_TESTCASE = Pattern.compile("(.*): error: -\\[(\\S+)\\s+(\\S+)\\] : (.*)");
    private static Pattern ERROR_UI_TESTCASE = Pattern.compile(".*?Assertion Failure: (.+:\\d+): (.*)");
    private static Pattern FAILED_TESTCASE = Pattern.compile("Test Case '-\\[(\\S+)\\s+(\\S+)\\]' failed \\((\\S+) seconds\\).");
    private static Pattern FAILED_WITH_EXIT_CODE = Pattern.compile("failed with exit code (\\d+)");
    private static Pattern TERMINATING_EXCEPTION = Pattern.compile(".*\\*\\*\\* Terminating app due to uncaught exception '(\\S+)', reason: '(.+[^\\\\])'.*");
    private File testReportsDir;
    protected OutputStream captureOutputStream;
    protected int exitCode;
    protected HashMap<String, TestSuite> testSuitesHash = new HashMap<String, TestSuite>();
    protected TestSuite currentTestSuite = null;
    protected TestCase currentTestCase = null;
    protected boolean consoleLog;

    protected XCodeBuildOutputParser() {
        super();
    }

    /**
     * Initalize the FilterOutputStream and prepare to generate the JUnit result files
     * @param workspace directory that will receive the result files
     * @param log the Xcode output stream that should be parsed
     */
    public XCodeBuildOutputParser(File workspace, OutputStream log) {
        this();
        this.captureOutputStream = new LineBasedFilterOutputStream(log);
        this.testReportsDir = workspace;
        this.consoleLog = true;
    }

    public class LineBasedFilterOutputStream extends FilterOutputStream {
        StringBuilder buffer = new StringBuilder();

        public LineBasedFilterOutputStream(OutputStream log) {
            super(log);
        }

        @Override
        public void write(int b) throws IOException {
            super.write(b);
            if((char)b == '\n') {
                try {
                    handleLine(buffer.toString());
                    buffer = new StringBuilder();
                } catch(Exception e) {  // Very fugly
                    throw new IOException(e);
                }
            } else {
                buffer.append((char)b);
            }
        }
    }

    private Date parseDate(String text) throws ParseException {
	Date date;
	ParseException parseException;

	date = null;
	parseException = null;

	for (DateFormat dateFormat : dateFormats) {
	    try {
		date = dateFormat.parse(text);
		break;
	    } catch (ParseException exception) {
		parseException = exception;
	    }
	}

	if ((date == null) && (parseException != null)) {
	    throw parseException;
	}

	return date;
    }

    private void requireTestSuite() {
	if(testSuitesHash.size()==0) {
	    throw new RuntimeException("Log statements out of sync: current test suite was empty");
	}
	if(currentTestSuite==null) {
	    throw new RuntimeException("Log statements out of sync: current test suite was null");
	}
    }

    private void requireTestSuite(String name) {
        currentTestSuite = testSuitesHash.get(name);
	if(currentTestSuite==null) {
	    // Swift 
	    String[] testSuites = name.split(Pattern.quote("."));
	    if ( testSuites.length == 2 ) {
		String xctestName = testSuites[0] + ".xctest";
		String testSuite = testSuites[1];
		if ( !testSuitesHash.containsKey(xctestName) ) {
		    throw new RuntimeException("Log statements out of sync: current test suite '" + xctestName + "' not exists");
		}
		currentTestSuite = testSuitesHash.get(testSuite);
		if ( currentTestSuite == null ) {
	    	    throw new RuntimeException("Log statements out of sync: current test suite '" + testSuite + "' not exists");
		}
	    }
	}
    }

    private void requireTestCase(String name) {
	currentTestCase = currentTestSuite.getTestCasesHash().get(name);
        if(currentTestCase==null) {
            throw new RuntimeException("Log statements out of sync: current test case '" + currentTestSuite.getName() + "." + name + "' not exists");
        }
    }

    private void writeTestReport() throws IOException, InterruptedException,
            JAXBException {
        try (OutputStream testReportOutputStream = outputForSuite()) {
            JAXBContext jaxbContext;
            Thread t = Thread.currentThread();
            ClassLoader orig = t.getContextClassLoader();
            t.setContextClassLoader(XCodeBuildOutputParser.class.getClassLoader());
            try {
                jaxbContext = JAXBContext.newInstance(TestSuite.class);
            } finally {
                t.setContextClassLoader(orig);
            }
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.marshal(currentTestSuite, testReportOutputStream);
        }
    }

    protected OutputStream outputForSuite() throws IOException,
            InterruptedException {
        return new FileOutputStream(new File(testReportsDir, "TEST-" + currentTestSuite.getName() + ".xml"));
    }

    protected void handleLine(String line) throws ParseException, IOException, InterruptedException, JAXBException {
        Matcher m = START_SUITE.matcher(line);
        if(m.matches()) {
	    if (testSuitesHash.isEmpty()) {
	    	consoleLog = true;
	    }
	    String suite_name = m.group(1);
	    if ( m.group(1).endsWith(".xctest") ) {
		suite_name = suite_name.replaceAll("-", "_");
	    }
            currentTestSuite = new TestSuite(InetAddress.getLocalHost().getHostName(), m.group(1), parseDate(m.group(2)));
	    testSuitesHash.put(suite_name, currentTestSuite);
            return;
        }

        m = END_SUITE.matcher(line);
        if(m.matches()) {
            String suite_name = m.group(1);
            if ( m.group(1).endsWith(".xctest") ) {
                suite_name = suite_name.replaceAll("-", "_");
            }
	    requireTestSuite(suite_name);
            currentTestSuite.setEndTime(parseDate(m.group(2)));
            writeTestReport();
            testSuitesHash.remove(suite_name);
	    currentTestSuite = null;
	    if ( testSuitesHash.size() == 1 ) {
		// If the last test suitev in nhash is Unknown, process it and exit.
		currentTestSuite = testSuitesHash.get("UnknownSuite");
		if ( currentTestSuite != null ) {
		    currentTestSuite.setEndTime(parseDate(m.group(2)));
		    writeTestReport();
		    testSuitesHash.remove(suite_name);
		    currentTestSuite = null;
		}
	    }
	    if (testSuitesHash.isEmpty()) {
                consoleLog = false;
	    }
            return;
        }

        m = START_TESTCASE.matcher(line);
        if(m.matches()) {
	    requireTestSuite(m.group(1));
	    currentTestCase = new TestCase(m.group(1), m.group(2));
            currentTestSuite.getTestCasesHash().put(m.group(2), currentTestCase);
            return;
        }

        m = END_TESTCASE.matcher(line);
        if(m.matches()) {
            requireTestSuite(m.group(1));
            requireTestCase(m.group(2));
            currentTestCase.setTime(Float.parseFloat(m.group(3)));
            currentTestSuite.getTestCases().add(currentTestCase);
            currentTestSuite.addTest();
	    // Actually, I think that the test case should be closed and deleted here.
	    // In case the error is reported late without synchronization.
	    //currentTestSuite.getTestCasesHash().remove(m.group(2));
	    currentTestCase = null;
	    return;
	}

        m = ERROR_TESTCASE.matcher(line);
        if(m.matches()) {
            String errorLocation = m.group(1);
            String testSuite = m.group(2);
            String testCase = m.group(3);
            String errorMessage = m.group(4);
            requireTestSuite(testSuite);
            requireTestCase(testCase);
            TestFailure failure = new TestFailure(errorMessage, errorLocation);
            currentTestCase.getFailures().add(failure);
            return;
        }

	// If the test result is returned asynchronously, there is a possibility
	//  that in this case the target test can not be decided and information
	//  is recorded in the wrong place.
        m = ERROR_UI_TESTCASE.matcher(line);
        if(m.matches()) {
            String errorLocation = m.group(1);
            String errorMessage = m.group(2);
            TestFailure failure = new TestFailure(errorMessage, errorLocation);

 	    if ( currentTestSuite == null ) {
		currentTestSuite = testSuitesHash.get("UnknownSuite");
		if ( currentTestSuite == null ) {
 		    currentTestSuite = new TestSuite(InetAddress.getLocalHost().getHostName(), "UnknownSuite", new Date());
		    testSuitesHash.put("UnknownSuite", currentTestSuite);
		}
 	    }
                  
	    if ( currentTestCase == null ) {
		currentTestCase = currentTestSuite.getTestCasesHash().get("UnknownTestCase");
		if ( currentTestCase == null ) {
		    currentTestCase = new TestCase(currentTestSuite.getName(), "UnknownTestCase");
		    currentTestSuite.getTestCasesHash().put("UnknownTestCase", currentTestCase);
		    currentTestSuite.getTestCases().add(currentTestCase);
		    currentTestSuite.addTest();
		}
	    }

            currentTestCase.getFailures().add(failure);
            return;
        }

        m = FAILED_TESTCASE.matcher(line);
        if(m.matches()) {
            requireTestSuite(m.group(1));
            requireTestCase(m.group(2));
            currentTestSuite.addTest();
            currentTestSuite.addFailure();
            currentTestCase.setTime(Float.parseFloat(m.group(3)));
            currentTestSuite.getTestCases().add(currentTestCase);
	    //currentTestSuite.getTestCasesHash().remove(m.group(2));
	    currentTestCase = null;
            return;
        }

        m = FAILED_WITH_EXIT_CODE.matcher(line);
        if(m.matches()) {
            exitCode = Integer.parseInt(m.group(1));
            return;
        }

        if(line.matches("BUILD FAILED") || line.matches("\\*\\* TEST FAILED \\*\\*")) {
            exitCode = -1;
        }
        
        m = TERMINATING_EXCEPTION.matcher(line);
        if(m.matches()) {
            exitCode = -1;
            requireTestSuite();
            if (currentTestCase != null) {
                TestError error = new TestError(m.group(2), m.group(1));
                currentTestCase.getErrors().add(error);
                currentTestSuite.getTestCases().add(currentTestCase);
                currentTestSuite.addTest();
                currentTestSuite.addError();
		//currentTestSuite.getTestCasesHash().remove(currentTestCase.getName());
                currentTestCase = null;
            }
            writeTestReport();
            currentTestSuite = null;
        }
    }

    public OutputStream getOutputStream() {
        return captureOutputStream;
    }

    public int getExitCode() {
        return exitCode;
    }
}


================================================
FILE: src/main/java/au/com/rayh/XCodeBuilder.java
================================================
/*
 * The MIT License
 *
 * Copyright (c) 2011 Ray Yamamoto Hilton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package au.com.rayh;

import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.*;
import hudson.security.ACL;
import hudson.util.FormValidation;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Builder;
import hudson.util.CopyOnWriteList;
import hudson.util.QuotedStringTokenizer;
import hudson.plugins.xcode.XcodeInstallation;
import hudson.util.Secret;
import jenkins.tasks.SimpleBuildStep;
import org.jenkinsci.Symbol;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
import org.jenkinsci.plugins.tokenmacro.TokenMacro;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import jenkins.model.Jenkins;

import javax.inject.Inject;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import java.util.UUID;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

import com.dd.plist.NSDictionary;
import com.dd.plist.PropertyListParser;

/**
 * @author Ray Hilton
 */
@SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
public class XCodeBuilder extends Builder implements SimpleBuildStep {

    private static final int SIGTERM = 143;
    private static final String DEVELOPMENT_ENV = "Development";
    private static final String PRODUCTION_ENV = "Production";
    private static final String DEV_SIGNING_CERTIFICATE_SELECTOR = "iOS Developer";
    private static final String DIST_SIGNING_CERTIFICATE_SELECTOR = "iOS Distribution";
    private static final String[] VALID_IPA_EXPORT_METHODS = { "development", "ad-hoc", "enterprise", "app-store" };

    /**
     * @since 1.0
     */
    @CheckForNull
    private Boolean cleanBeforeBuild;
    /**
     * @since 1.3
     */
    @CheckForNull
    private Boolean cleanTestReports;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String configuration;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String target;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String sdk;
    /**
     * @since 1.1
     */
    @CheckForNull
    private String symRoot;
    /**
     * @since 1.2
     */
    @CheckForNull
    private String buildDir;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String xcodeProjectPath;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String xcodeProjectFile;
    /**
     * @since 1.3
     */
    @CheckForNull
    private String xcodebuildArguments;
    /**
     * @since 1.2
     */
    @CheckForNull
    private String xcodeSchema;
    /**
     * @since 1.2
     */
    @CheckForNull
    private String xcodeWorkspaceFile;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String cfBundleVersionValue;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String cfBundleShortVersionStringValue;
    /**
     * @since 1.0
     */
    @CheckForNull
    private Boolean buildIpa;
    /**
     * @since 1.4.12
     */
    @CheckForNull
    private String ipaExportMethod;
    /**
     * @since 1.0
     */
    @CheckForNull
    private Boolean generateArchive;
    /**
     * @since 2.0.1
     */
    @CheckForNull
    private Boolean noConsoleLog;
    /**
     * @since 2.0.1
     */
    @CheckForNull
    private String logfileOutputDirectory;
    /**
     * @since 1.5
     **/
    @CheckForNull
    private Boolean unlockKeychain;
    /**
     * @since 1.4
     */
    @Deprecated
    @CheckForNull
    private String keychainName;
    /**
     * @since 2.0.12
     */
    @CheckForNull
    private String keychainId;
    /**
     * @since 1.0
     */
    @CheckForNull
    private String keychainPath;
    /**
     * @since 1.0
     */
    @CheckForNull
    private Secret keychainPwd;
    /**
     * @since 1.4.12
     */
    @CheckForNull
    private String developmentTeamName;
    /**
     * @since 1.4.12
     */
    @CheckForNull
    private String developmentTeamID;
    /**
     * @since 1.4
     */
    @CheckForNull
    private Boolean allowFailingBuildResults;
    /**
     * @since 1.4
     */
    @CheckForNull
    private String ipaName;
    /**
     * @since 1.4
     */
    @CheckForNull
    private String ipaOutputDirectory;
    /**
     * @since 1.4
     */
    @CheckForNull
    private Boolean provideApplicationVersion;
    /**
     * @since 1.4
     */
    @CheckForNull
    private Boolean changeBundleID;
    /**
     * @since 1.4
     */
    @CheckForNull
    private String bundleID;
    /**
     * @since 1.4
     */
    @CheckForNull
    private String bundleIDInfoPlistPath;
    /**
     * @since 1.4
     */
    @CheckForNull
    private Boolean interpretTargetAsRegEx;
    /**
     * @deprecated 2.0.3
     *
    @CheckForNull
    private String ipaManifestPlistUrl;
     */
    /**
     * @deprecated 2.0.7
     *
    @CheckForNull
    private Boolean manualSigning;
     */
    /**
     * @since 2.0.7
     */
    @CheckForNull
    private String signingMethod;
    /**
     * @since 2.0.1
     */
    @CheckForNull
    private ArrayList<ProvisioningProfile> provisioningProfiles;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private String xcodeName;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private Boolean uploadBitcode;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private Boolean uploadSymbols;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private Boolean compileBitcode;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private String thinning;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private Boolean embedOnDemandResourcesAssetPacksInBundle;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private String onDemandResourcesAssetPacksBaseURL;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private String appURL;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private String displayImageURL;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private String fullSizeImageURL;
    /*
     * @since 2.0.3
     */
    @CheckForNull
    private String assetPackManifestURL;
    /**
     * @since 2.0.3
     */
    @CheckForNull
    private Boolean skipBuildStep;
    /**
     * @since 2.0.5
     */
    @CheckForNull
    private Boolean stripSwiftSymbols;
    /**
     * @since 2.0.7
     */
    @CheckForNull
    private Boolean copyProvisioningProfile;
    /**
     * @since 2.0.9
     */
    @CheckForNull
    private Boolean useLegacyBuildSystem;
    /**
     * @since 2.0.11
     */
    @CheckForNull
    private Boolean ignoreTestResults;
    /**
     * @since 2.0.11
     */
    @CheckForNull
    private String resultBundlePath;
    /**
     * @since 2.0.11
     */
    @CheckForNull
    private Boolean cleanResultBundlePath;

    public Boolean getCleanBeforeBuild() {
	return cleanBeforeBuild == null ? Boolean.valueOf(true) : cleanBeforeBuild;
    }

    @DataBoundSetter
    public void setCleanBeforeBuild(Boolean cleanBeforeBuild) {
	this.cleanBeforeBuild = cleanBeforeBuild;
    }

    public Boolean getCleanTestReports() {
	return cleanTestReports == null ? Boolean.valueOf(false) : cleanTestReports;
    }

    @DataBoundSetter
    public void setCleanTestReports(Boolean cleanTestReports) {
	this.cleanTestReports = cleanTestReports;
    }

    @CheckForNull
    public String getConfiguration() {
	return configuration;
    }

    @DataBoundSetter
    public void setConfiguration(String configuration) {
	this.configuration = configuration;
    }

    @CheckForNull
    public String getTarget() {
	return target;
    }

    @DataBoundSetter
    public void setTarget(String target) {
	this.target = target;
    }

    @CheckForNull
    public String getSdk() {
	return sdk;
    }

    @DataBoundSetter
    public void setSdk(String sdk) {
	this.sdk = sdk;
    }

    @CheckForNull
    public String getSymRoot() {
	return symRoot;
    }

    @DataBoundSetter
    public void setSymRoot(String symRoot) {
	this.symRoot = symRoot;
    }

    @CheckForNull
    public String getBuildDir() {
	return buildDir;
    }

    @DataBoundSetter
    public void setBuildDir(String buildDir) {
	this.buildDir = buildDir;
    }

    @CheckForNull
    public String getXcodeProjectPath() {
	return xcodeProjectPath;
    }

    @DataBoundSetter
    public void setXcodeProjectPath(String xcodeProjectPath) {
	this.xcodeProjectPath = xcodeProjectPath;
    }

    @CheckForNull
    public String getXcodeProjectFile() {
	return xcodeProjectFile;
    }

    @DataBoundSetter
    public void setXcodeProjectFile(String xcodeProjectFile) {
	this.xcodeProjectFile = xcodeProjectFile;
    }

    @CheckForNull
    public String getXcodebuildArguments() {
	return xcodebuildArguments;
    }

    @DataBoundSetter
    public void setXcodebuildArguments(String xcodebuildArguments) {
	this.xcodebuildArguments = xcodebuildArguments;
    }

    @CheckForNull
    public String getXcodeSchema() {
	return xcodeSchema;
    }

    @DataBoundSetter
    public void setXcodeSchema(String xcodeSchema) {
	this.xcodeSchema = xcodeSchema;
    }

    @CheckForNull
    public String getXcodeWorkspaceFile() {
	return xcodeWorkspaceFile;
    }

    @DataBoundSetter
    public void setXcodeWorkspaceFile(String xcodeWorkspaceFile) {
	this.xcodeWorkspaceFile = xcodeWorkspaceFile;
    }

    @CheckForNull
    public String getCfBundleVersionValue() {
	return cfBundleVersionValue;
    }

    @DataBoundSetter
    public void setCfBundleVersionValue(String cfBundleVersionValue) {
	this.cfBundleVersionValue = cfBundleVersionValue;
    }

    @CheckForNull
    public String getCfBundleShortVersionStringValue() {
	return cfBundleShortVersionStringValue;
    }

    @DataBoundSetter
    public void setCfBundleShortVersionStringValue(String cfBundleShortVersionStringValue) {
	this.cfBundleShortVersionStringValue = cfBundleShortVersionStringValue;
    }

    public Boolean getBuildIpa() {
	return buildIpa == null ? Boolean.valueOf(false) : buildIpa;
    }

    @DataBoundSetter
    public void setBuildIpa(Boolean buildIpa) {
	this.buildIpa = buildIpa;
    }

    public String getIpaExportMethod() {
	return ipaExportMethod == null ? "app-store" : ipaExportMethod;
    }

    @DataBoundSetter
    public void setIpaExportMethod(String ipaExportMethod) {
	this.ipaExportMethod = ipaExportMethod;
    }

    public Boolean getGenerateArchive() {
	return generateArchive == null ? Boolean.valueOf(false) : generateArchive;
    }

    @DataBoundSetter
    public void setGenerateArchive(Boolean generateArchive) {
	this.generateArchive = generateArchive;
    }

    public Boolean getNoConsoleLog() {
	return noConsoleLog == null ? Boolean.valueOf(false) : noConsoleLog;
    }

    @DataBoundSetter
    public void setNoConsoleLog(Boolean noConsoleLog) {
	this.noConsoleLog = noConsoleLog;
    }

    @CheckForNull
    public String getLogfileOutputDirectory() {
	return logfileOutputDirectory;
    }

    @DataBoundSetter
    public void setLogfileOutputDirectory(String logfileOutputDirectory) {
	this.logfileOutputDirectory = logfileOutputDirectory;
    }

    public Boolean getUnlockKeychain() {
	return unlockKeychain == null ? Boolean.valueOf(false) : unlockKeychain;
    }

    @DataBoundSetter
    public void setUnlockKeychain(Boolean unlockKeychain) {
	this.unlockKeychain = unlockKeychain;
    }

    @Deprecated
    @CheckForNull
    public String getKeychainName() {
	return keychainName;
    }

    @CheckForNull
    public String getKeychainId() {
        return keychainId;
    }

    @Deprecated
    @DataBoundSetter
    public void setKeychainName(String keychainName) {
	this.keychainName = keychainName;
    }

    @DataBoundSetter
    public void setKeychainId(String keychainId) {
        this.keychainId = keychainId;
    }

    @CheckForNull
    public String getKeychainPath() {
	return keychainPath;
    }

    @DataBoundSetter
    public void setKeychainPath(String keychainPath) {
	this.keychainPath = keychainPath;
    }

    @CheckForNull
    public Secret getKeychainPwd() {
	return keychainPwd;
    }

    @DataBoundSetter
    public void setKeychainPwd(Secret keychainPwd) {
	this.keychainPwd = keychainPwd;
    }

    @CheckForNull
    public String getDevelopmentTeamName() {
	return developmentTeamName;
    }

    @DataBoundSetter
    public void setDevelopmentTeamName(String developmentTeamName) {
	this.developmentTeamName = developmentTeamName;
    }

    @CheckForNull
    public String getDevelopmentTeamID() {
	return developmentTeamID;
    }

    @DataBoundSetter
    public void setDevelopmentTeamID(String developmentTeamID) {
	this.developmentTeamID = developmentTeamID;
    }

    public Boolean getAllowFailingBuildResults() {
	return allowFailingBuildResults == null ? Boolean.valueOf(false) : allowFailingBuildResults;
    }

    @DataBoundSetter
    public void setAllowFailingBuildResults(Boolean allowFailingBuildResults) {
	this.allowFailingBuildResults = allowFailingBuildResults;
    }

    @CheckForNull
    public String getIpaName() {
	return ipaName;
    }

    @DataBoundSetter
    public void setIpaName(String ipaName) {
	this.ipaName = ipaName;
    }

    @CheckForNull
    public String getIpaOutputDirectory() {
	return ipaOutputDirectory;
    }

    @DataBoundSetter
    public void setIpaOutputDirectory(String ipaOutputDirectory) {
	this.ipaOutputDirectory = ipaOutputDirectory;
    }

    public Boolean getProvideApplicationVersion() {
	return provideApplicationVersion == null ? Boolean.valueOf(false) : provideApplicationVersion;
    }

    @DataBoundSetter
    public void setProvideApplicationVersion(Boolean provideApplicationVersion) {
	this.provideApplicationVersion = provideApplicationVersion;
    }

    public Boolean getChangeBundleID() {
	return changeBundleID == null ? Boolean.valueOf(false) : changeBundleID;
    }

    @DataBoundSetter
    public void setChangeBundleID(Boolean changeBundleID) {
	this.changeBundleID = changeBundleID;
    }

    @CheckForNull
    public String getBundleID() {
	return bundleID;
    }

    @DataBoundSetter
    public void setBundleID(String bundleID) {
	this.bundleID = bundleID;
    }

    @CheckForNull
    public String getBundleIDInfoPlistPath() {
	return bundleIDInfoPlistPath;
    }

    @DataBoundSetter
    public void setBundleIDInfoPlistPath(String bundleIDInfoPlistPath) {
	this.bundleIDInfoPlistPath = bundleIDInfoPlistPath;
    }

    public Boolean getInterpretTargetAsRegEx() {
	return interpretTargetAsRegEx == null ? Boolean.valueOf(false) : interpretTargetAsRegEx;
    }

    @DataBoundSetter
    public void setInterpretTargetAsRegEx(Boolean interpretTargetAsRegEx) {
	this.interpretTargetAsRegEx = interpretTargetAsRegEx;
    }

    @Deprecated
    public Boolean getManualSigning() {
	return ( signingMethod == null || signingMethod.equals("manual") );
    }

    @Deprecated
    @DataBoundSetter
    public void setManualSigning(Boolean manualSigning) {
	this.signingMethod = BooleanUtils.isTrue(manualSigning) ? "manual" : "automatic";
    }

    public String getSigningMethod() {
	return signingMethod == null ? "automatic" : signingMethod;
    }

    @DataBoundSetter
    public void setSigningMethod(String signingMethod) {
	this.signingMethod = signingMethod;
    }

    @CheckForNull
    public ArrayList<ProvisioningProfile> getProvisioningProfiles() {
	return provisioningProfiles;
    }

    @DataBoundSetter
    public void setProvisioningProfiles(ArrayList<ProvisioningProfile> provisioningProfiles) {
	this.provisioningProfiles = provisioningProfiles;
    }

    @CheckForNull
    public String getXcodeName() {
	return xcodeName;
    }

    @DataBoundSetter
    public void setXcodeName(String xcodeName) {
	this.xcodeName = xcodeName;
    }

    public Boolean getUploadBitcode() {
	return uploadBitcode == null ? Boolean.valueOf(true) : uploadBitcode;
    }

    @DataBoundSetter
    public void setUploadBitcode(Boolean uploadBitcode) {
	this.uploadBitcode = uploadBitcode;
    }

    public Boolean getUploadSymbols() {
	return uploadSymbols == null ? Boolean.valueOf(true) : uploadSymbols;
    }

    @DataBoundSetter
    public void setUploadSymbols(Boolean uploadSymbols) {
	this.uploadSymbols = uploadSymbols;
    }

    public Boolean getCompileBitcode() {
	return compileBitcode == null ? Boolean.valueOf(true) : compileBitcode;
    }

    @DataBoundSetter
    public void setCompileBitcode(Boolean compileBitcode) {
	this.compileBitcode = compileBitcode;
    }

    @CheckForNull
    public String getThinning() {
	return thinning;
    }

    @DataBoundSetter
    public void setThinning(String thinning) {
	this.thinning = thinning;
    }

    public Boolean getAssetPacksInBundle() {
	return embedOnDemandResourcesAssetPacksInBundle == null ? Boolean.valueOf(true) : embedOnDemandResourcesAssetPacksInBundle;
    }

    @DataBoundSetter
    public void setAssetPacksInBundle(Boolean assetPacksInBundle) {
	this.embedOnDemandResourcesAssetPacksInBundle = assetPacksInBundle;
    }

    @CheckForNull
    public String getAssetPacksBaseURL() {
	return onDemandResourcesAssetPacksBaseURL;
    }

    @DataBoundSetter
    public void setAssetPacksBaseURL(String assetPacksBaseURL) {
	this.onDemandResourcesAssetPacksBaseURL = assetPacksBaseURL;
    }

    @CheckForNull
    public String getAppURL() {
	return appURL;
    }

    @DataBoundSetter
    public void setAppURL(String appURL) {
	this.appURL = appURL;
    }

    @CheckForNull
    public String getDisplayImageURL() {
	return displayImageURL;
    }

    @DataBoundSetter
    public void setDisplayImageURL(String displayImageURL) {
	this.displayImageURL = displayImageURL;
    }

    @CheckForNull
    public String getFullSizeImageURL() {
	return fullSizeImageURL;
    }

    @DataBoundSetter
    public void setFullSizeImageURL(String fullSizeImageURL) {
	this.fullSizeImageURL = fullSizeImageURL;
    }

    @CheckForNull
    public String getAssetPackManifestURL() {
	return assetPackManifestURL;
    }

    @DataBoundSetter
    public void setAssetPackManifestURL(String assetPackManifestURL) {
	this.assetPackManifestURL = assetPackManifestURL;
    }

    public Boolean getStripSwiftSymbols() {
	return stripSwiftSymbols == null ? Boolean.valueOf(true) : stripSwiftSymbols;
    }

    @DataBoundSetter
    public void setStripSwiftSymbols(Boolean stripSwiftSymbols) {
	this.stripSwiftSymbols = stripSwiftSymbols;
    }

    public Boolean getCopyProvisioningProfile() {
	return copyProvisioningProfile == null ? Boolean.valueOf(true) : copyProvisioningProfile;
    }

    @DataBoundSetter
    public void setCopyProvisioningProfile(Boolean copyProvisioningProfile) {
	this.copyProvisioningProfile = copyProvisioningProfile;
    }

    public Boolean getUseLegacyBuildSystem() {
	return useLegacyBuildSystem == null ? Boolean.valueOf(false) : useLegacyBuildSystem;
    }

    @DataBoundSetter
    public void setUseLegacyBuildSystem(Boolean useLegacyBuildSystem) {
	this.useLegacyBuildSystem = useLegacyBuildSystem;
    }

    public Boolean getIgnoreTestResults() {
	return ignoreTestResults == null ? Boolean.valueOf(false) : ignoreTestResults;
    }

    @DataBoundSetter
    public void setIgnoreTestResults(Boolean ignoreTestResults) {
	this.ignoreTestResults = ignoreTestResults;
    }

    public String getResultBundlePath() {
        return resultBundlePath;
    }

    @DataBoundSetter
    public void setResultBundlePath(String resultBundlePath) {
        this.resultBundlePath = resultBundlePath;
    }

    @DataBoundSetter
    public void setCleanResultBundlePath(Boolean cleanResultBundlePath) {
        this.cleanResultBundlePath = cleanResultBundlePath;
    }

    public Boolean getCleanResultBundlePath() {
        return cleanResultBundlePath == null ? Boolean.valueOf(true) : cleanResultBundlePath;
    }

    // Internally.
    public void setSkipBuildStep(Boolean skipBuildStep) {
        this.skipBuildStep = skipBuildStep;
    }

    // Fields in config.jelly must match the parameter names in the "DataBoundConstructor"
    @DataBoundConstructor
    public XCodeBuilder() {
	this.skipBuildStep = Boolean.valueOf(false);
    }

    @Deprecated
    public XCodeBuilder(Boolean buildIpa, Boolean generateArchive, Boolean noConsoleLog, String logfileOutputDirectory, Boolean cleanBeforeBuild, 
    		Boolean cleanTestReports, String configuration,
    		String target, String sdk, String xcodeProjectPath, String xcodeProjectFile, String xcodebuildArguments,
    		String cfBundleVersionValue, String cfBundleShortVersionStringValue, Boolean unlockKeychain,
    		String keychainName, String keychainPath, String keychainPwd, String symRoot, String xcodeWorkspaceFile,
    		String xcodeSchema, String buildDir, String developmentTeamName, String developmentTeamID, Boolean allowFailingBuildResults,
    		String ipaName, Boolean provideApplicationVersion, String ipaOutputDirectory, Boolean changeBundleID, String bundleID,
    		String bundleIDInfoPlistPath, Boolean interpretTargetAsRegEx, String ipaExportMethod,
		String signingMethod, ArrayList<ProvisioningProfile> provisioningProfiles, String xcodeName,
		Boolean uploadBitcode, Boolean uploadSymbols, Boolean compileBitcode, String thinning,
		Boolean embedOnDemandResourcesAssetPacksInBundle, String onDemandResourcesAssetPacksBaseURL,
		String appURL, String displayImageURL, String fullSizeImageURL,
		String assetPackManifestURL) {
	this();
        this.buildIpa = buildIpa;
        this.generateArchive = generateArchive;
        this.noConsoleLog = noConsoleLog;
        this.logfileOutputDirectory = logfileOutputDirectory;
        this.sdk = sdk;
        this.target = target;
        this.cleanBeforeBuild = cleanBeforeBuild;
        this.cleanTestReports = cleanTestReports;
        this.configuration = configuration;
        this.xcodeProjectPath = xcodeProjectPath;
        this.xcodeProjectFile = xcodeProjectFile;
        this.xcodebuildArguments = xcodebuildArguments;
        this.keychainName = keychainName;
        this.xcodeWorkspaceFile = xcodeWorkspaceFile;
        this.xcodeSchema = xcodeSchema;
        this.developmentTeamName = developmentTeamName;
        this.developmentTeamID = developmentTeamID;
        this.cfBundleVersionValue = cfBundleVersionValue;
        this.cfBundleShortVersionStringValue = cfBundleShortVersionStringValue;
        this.unlockKeychain = unlockKeychain;
        this.keychainPath = keychainPath;
        this.keychainPwd = Secret.fromString(keychainPwd);
        this.symRoot = symRoot;
        this.buildDir = buildDir;
        this.allowFailingBuildResults = allowFailingBuildResults;
        this.ipaName = ipaName;
        this.ipaOutputDirectory = ipaOutputDirectory;
        this.provideApplicationVersion = provideApplicationVersion;
        this.changeBundleID = changeBundleID;
        this.bundleID = bundleID;
        this.bundleIDInfoPlistPath = bundleIDInfoPlistPath;
        this.interpretTargetAsRegEx = interpretTargetAsRegEx;
        //this.ipaManifestPlistUrl = null;
        this.ipaExportMethod = ipaExportMethod;
        this.signingMethod = signingMethod;
        this.provisioningProfiles = provisioningProfiles;
	this.xcodeName = xcodeName;
	this.uploadBitcode = uploadBitcode;
	this.uploadSymbols = uploadSymbols;
	this.compileBitcode = compileBitcode;
	this.thinning = thinning;
	this.embedOnDemandResourcesAssetPacksInBundle = embedOnDemandResourcesAssetPacksInBundle;
	this.onDemandResourcesAssetPacksBaseURL = onDemandResourcesAssetPacksBaseURL;

	this.appURL = appURL;
	this.displayImageURL = displayImageURL;
	this.fullSizeImageURL = fullSizeImageURL;
	this.assetPackManifestURL = assetPackManifestURL;
	this.stripSwiftSymbols = Boolean.valueOf(true);

	this.skipBuildStep = Boolean.valueOf(false);
    }

    @Deprecated
    public XCodeBuilder(Boolean buildIpa, Boolean generateArchive, Boolean noConsoleLog, String logfileOutputDirectory, Boolean cleanBeforeBuild,
			Boolean cleanTestReports, String configuration,
			String target, String sdk, String xcodeProjectPath, String xcodeProjectFile, String xcodebuildArguments,
			String cfBundleVersionValue, String cfBundleShortVersionStringValue, Boolean unlockKeychain,
			String keychainName, String keychainPath, String keychainPwd, String symRoot, String xcodeWorkspaceFile,
			String xcodeSchema, String buildDir, String developmentTeamName, String developmentTeamID, Boolean allowFailingBuildResults,
			String ipaName, Boolean provideApplicationVersion, String ipaOutputDirectory, Boolean changeBundleID, String bundleID,
			String bundleIDInfoPlistPath, String ipaManifestPlistUrl, Boolean interpretTargetAsRegEx, String ipaExportMethod,
			String signingMethod, ArrayList<ProvisioningProfile> provisioningProfiles, String xcodeName) {
	this(buildIpa, generateArchive, noConsoleLog, logfileOutputDirectory, cleanBeforeBuild, cleanTestReports, configuration,
		target, sdk, xcodeProjectPath, xcodeProjectFile, xcodebuildArguments,
		cfBundleVersionValue, cfBundleShortVersionStringValue, unlockKeychain,
		keychainName, keychainPath, keychainPwd, symRoot, xcodeWorkspaceFile,
		xcodeSchema, buildDir, developmentTeamName, developmentTeamID, allowFailingBuildResults,
		ipaName, provideApplicationVersion, ipaOutputDirectory, changeBundleID, bundleID,
		bundleIDInfoPlistPath, interpretTargetAsRegEx, ipaExportMethod,
		signingMethod, provisioningProfiles, xcodeName, true, true, true, null, false, null, ipaManifestPlistUrl, null, null, null);
    }

    @Deprecated
    public XCodeBuilder(Boolean buildIpa, Boolean generateArchive, Boolean noConsoleLog, String logfileOutputDirectory, Boolean cleanBeforeBuild,
                        Boolean cleanTestReports, String configuration,
             
Download .txt
gitextract_872818gr/

├── .github/
│   ├── dependabot.yml
│   ├── release-drafter.yml
│   └── workflows/
│       └── cd.yaml
├── .gitignore
├── .mvn/
│   ├── extensions.xml
│   └── maven.config
├── CHANGELOG.md
├── Jenkinsfile
├── README.md
├── docs/
│   └── images/
│       └── e75543fce396e66c1ad66700d6e74156c2b730db.logo
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   ├── au/
    │   │   │   └── com/
    │   │   │       └── rayh/
    │   │   │           ├── BuildConfiguration.java
    │   │   │           ├── DSymFileFilter.java
    │   │   │           ├── DeveloperProfile.java
    │   │   │           ├── DeveloperProfileLoader.java
    │   │   │           ├── ExportIpa.java
    │   │   │           ├── GlobalConfigurationImpl.java
    │   │   │           ├── InfoPlist.java
    │   │   │           ├── JenkinsXCodeBuildOutputParser.java
    │   │   │           ├── Keychain.java
    │   │   │           ├── KeychainPasswordAndPath.java
    │   │   │           ├── KeychainPasswordAndPathBinding.java
    │   │   │           ├── KeychainPasswordAndPathImpl.java
    │   │   │           ├── KeychainUnlockStep.java
    │   │   │           ├── MobileProvisionParser.java
    │   │   │           ├── ProjectScheme.java
    │   │   │           ├── ProjectTarget.java
    │   │   │           ├── ProvisioningProfile.java
    │   │   │           ├── Team.java
    │   │   │           ├── XCArchiveFileFilter.java
    │   │   │           ├── XCodeAction.java
    │   │   │           ├── XCodeBuildNumberTokenMacro.java
    │   │   │           ├── XCodeBuildOutputParser.java
    │   │   │           ├── XCodeBuilder.java
    │   │   │           ├── XcodeBuildHelpParser.java
    │   │   │           ├── XcodeBuildListParser.java
    │   │   │           ├── XcodeCredentialsHelper.java
    │   │   │           ├── XcodeDeclarativeCredentialsHandler.java
    │   │   │           ├── XcodeProject.java
    │   │   │           ├── XcodeProjectFileFilter.java
    │   │   │           ├── XcodeProjectParser.java
    │   │   │           ├── XcodeSchemeFileFilter.java
    │   │   │           ├── XcodeTestSummariesParser.java
    │   │   │           └── report/
    │   │   │               ├── TestCase.java
    │   │   │               ├── TestError.java
    │   │   │               ├── TestFailure.java
    │   │   │               └── TestSuite.java
    │   │   └── hudson/
    │   │       └── plugins/
    │   │           └── xcode/
    │   │               └── XcodeInstallation.java
    │   ├── resources/
    │   │   ├── au/
    │   │   │   └── com/
    │   │   │       └── rayh/
    │   │   │           ├── DeveloperProfile/
    │   │   │           │   ├── config.groovy
    │   │   │           │   ├── config_ja.properties
    │   │   │           │   ├── help-description.html
    │   │   │           │   ├── help-description_ja.html
    │   │   │           │   ├── help-password.html
    │   │   │           │   ├── help-password_ja.html
    │   │   │           │   ├── help.html
    │   │   │           │   ├── help_ja.html
    │   │   │           │   └── upload.groovy
    │   │   │           ├── DeveloperProfileLoader/
    │   │   │           │   ├── config.jelly
    │   │   │           │   └── config_ja.properties
    │   │   │           ├── ExportIpa/
    │   │   │           │   ├── config.jelly
    │   │   │           │   ├── config_ja.properties
    │   │   │           │   ├── help-archiveDir.html
    │   │   │           │   └── help-archiveDir_ja.html
    │   │   │           ├── GlobalConfigurationImpl/
    │   │   │           │   ├── config.jelly
    │   │   │           │   └── config_ja.properties
    │   │   │           ├── KeychainPasswordAndPathBinding/
    │   │   │           │   ├── config-variables.jelly
    │   │   │           │   ├── config-variables_ja.properties
    │   │   │           │   ├── help-inSearchPathVariable.html
    │   │   │           │   ├── help-inSearchPathVariable_ja.html
    │   │   │           │   ├── help-keychainPathVariable.html
    │   │   │           │   ├── help-keychainPathVariable_ja.html
    │   │   │           │   ├── help-passwordVariable.html
    │   │   │           │   └── help-passwordVariable_ja.html
    │   │   │           ├── KeychainPasswordAndPathImpl/
    │   │   │           │   ├── credentials.jelly
    │   │   │           │   ├── credentials_ja.properties
    │   │   │           │   ├── help-description.html
    │   │   │           │   ├── help-description_ja.html
    │   │   │           │   ├── help-id.html
    │   │   │           │   ├── help-id_ja.html
    │   │   │           │   ├── help-keychainPath.html
    │   │   │           │   ├── help-keychainPath_ja.html
    │   │   │           │   ├── help-password.html
    │   │   │           │   └── help-password_ja.html
    │   │   │           ├── KeychainUnlockStep/
    │   │   │           │   ├── config.jelly
    │   │   │           │   └── config_ja.properties
    │   │   │           ├── Messages.properties
    │   │   │           ├── Messages_ja.properties
    │   │   │           └── XCodeBuilder/
    │   │   │               ├── config.jelly
    │   │   │               ├── config_ja.properties
    │   │   │               ├── help-allowFailingBuildResults.html
    │   │   │               ├── help-allowFailingBuildResults_ja.html
    │   │   │               ├── help-buildDir.html
    │   │   │               ├── help-buildDir_ja.html
    │   │   │               ├── help-buildIpa.html
    │   │   │               ├── help-buildIpa_ja.html
    │   │   │               ├── help-bundleID.html
    │   │   │               ├── help-bundleIDInfoPlistPath.html
    │   │   │               ├── help-bundleIDInfoPlistPath_ja.html
    │   │   │               ├── help-bundleID_ja.html
    │   │   │               ├── help-cfBundleShortVersionStringValue.html
    │   │   │               ├── help-cfBundleShortVersionStringValue_ja.html
    │   │   │               ├── help-cfBundleVersionValue.html
    │   │   │               ├── help-cfBundleVersionValue_ja.html
    │   │   │               ├── help-changeBundleID.html
    │   │   │               ├── help-changeBundleID_ja.html
    │   │   │               ├── help-cleanBeforeBuild.html
    │   │   │               ├── help-cleanBeforeBuild_ja.html
    │   │   │               ├── help-cleanResultBundlePath.html
    │   │   │               ├── help-cleanResultBundlePath_ja.html
    │   │   │               ├── help-codeSigningIdentity.html
    │   │   │               ├── help-codeSigningIdentity_ja.html
    │   │   │               ├── help-configuration.html
    │   │   │               ├── help-configuration_ja.html
    │   │   │               ├── help-embeddedProfileFile.html
    │   │   │               ├── help-embeddedProfileFile_ja.html
    │   │   │               ├── help-generateArchive.html
    │   │   │               ├── help-generateArchive_ja.html
    │   │   │               ├── help-globalDevelopmentTeam_ja.html
    │   │   │               ├── help-globalKeychainName_ja.html
    │   │   │               ├── help-interpretTargetAsRegEx.html
    │   │   │               ├── help-interpretTargetAsRegEx_ja.html
    │   │   │               ├── help-ipaName_ja.html
    │   │   │               ├── help-keychainName.html
    │   │   │               ├── help-keychainName_ja.html
    │   │   │               ├── help-keychainPath.html
    │   │   │               ├── help-keychainPath_ja.html
    │   │   │               ├── help-keychainPwd.html
    │   │   │               ├── help-keychainPwd_ja.html
    │   │   │               ├── help-logfileOutputDirectory.html
    │   │   │               ├── help-logfileOutputDirectory_ja.html
    │   │   │               ├── help-resultBundlePath.html
    │   │   │               ├── help-resultBundlePath_ja.html
    │   │   │               ├── help-sdk.html
    │   │   │               ├── help-sdk_ja.html
    │   │   │               ├── help-signIpaOnXcrun.html
    │   │   │               ├── help-signIpaOnXcrun_ja.html
    │   │   │               ├── help-symRoot.html
    │   │   │               ├── help-symRoot_ja.html
    │   │   │               ├── help-target.html
    │   │   │               ├── help-target_ja.html
    │   │   │               ├── help-unlockKeychain_ja.html
    │   │   │               ├── help-useLegacyBuildSystem.html
    │   │   │               ├── help-useLegacyBuildSystem_ja.html
    │   │   │               ├── help-xcodeProjectFile_ja.html
    │   │   │               ├── help-xcodeProjectPath_ja.html
    │   │   │               ├── help-xcodeSchema_ja.html
    │   │   │               ├── help-xcodeWorkspaceFile_ja.html
    │   │   │               ├── help-xcodebuildArguments.html
    │   │   │               └── help-xcodebuildArguments_ja.html
    │   │   ├── hudson/
    │   │   │   └── plugins/
    │   │   │       └── xcode/
    │   │   │           └── XcodeInstallation/
    │   │   │               ├── config.jelly
    │   │   │               ├── config_it.properties
    │   │   │               ├── config_ja.properties
    │   │   │               ├── help-home.html
    │   │   │               └── help-home_ja.html
    │   │   └── index.jelly
    │   └── webapp/
    │       ├── help/
    │       │   ├── help-appIDandProvisionUUID.html
    │       │   ├── help-appIDandProvisionUUID_ja.html
    │       │   ├── help-assetPackManifestURL.html
    │       │   ├── help-assetPackManifestURL_ja.html
    │       │   ├── help-automaticSigning.html
    │       │   ├── help-automaticSigning_ja.html
    │       │   ├── help-bundleID.html
    │       │   ├── help-bundleID_ja.html
    │       │   ├── help-compileBitcode.html
    │       │   ├── help-compileBitcode_ja.html
    │       │   ├── help-copyProvisioningProfile.html
    │       │   ├── help-copyProvisioningProfile_ja.html
    │       │   ├── help-credentialKeychainId.html
    │       │   ├── help-credentialKeychainId_ja.html
    │       │   ├── help-developmentTeamID.html
    │       │   ├── help-developmentTeamID_ja.html
    │       │   ├── help-displayImageURL.html
    │       │   ├── help-displayImageURL_ja.html
    │       │   ├── help-embedOnDemandResources.html
    │       │   ├── help-embedOnDemandResources_ja.html
    │       │   ├── help-fullSizeImageURL.html
    │       │   ├── help-fullSizeImageURL_ja.html
    │       │   ├── help-globalDevelopmentTeam.html
    │       │   ├── help-globalDevelopmentTeam_ja.html
    │       │   ├── help-globalKeychainName.html
    │       │   ├── help-globalKeychainName_ja.html
    │       │   ├── help-importDeveloperProfile.html
    │       │   ├── help-importDeveloperProfileId.html
    │       │   ├── help-importDeveloperProfileId_ja.html
    │       │   ├── help-importDeveloperProfile_ja.html
    │       │   ├── help-importIntoExistingKeychain.html
    │       │   ├── help-importIntoExistingKeychain_ja.html
    │       │   ├── help-importKeychainId.html
    │       │   ├── help-importKeychainId_ja.html
    │       │   ├── help-importKeychainName.html
    │       │   ├── help-importKeychainName_ja.html
    │       │   ├── help-ipaExportMethod.html
    │       │   ├── help-ipaExportMethod_ja.html
    │       │   ├── help-ipaManifestPlistUrl.html
    │       │   ├── help-ipaManifestPlistUrl_ja.html
    │       │   ├── help-ipaName.html
    │       │   ├── help-ipaName_ja.html
    │       │   ├── help-ipaOutputDirectory.html
    │       │   ├── help-ipaOutputDirectory_ja.html
    │       │   ├── help-manifestPlistURL.html
    │       │   ├── help-manifestPlistURL_ja.html
    │       │   ├── help-manualSigning.html
    │       │   ├── help-manualSigning_ja.html
    │       │   ├── help-onDemandResourcesURL.html
    │       │   ├── help-onDemandResourcesURL_ja.html
    │       │   ├── help-provisioningUUID.html
    │       │   ├── help-provisioningUUID_ja.html
    │       │   ├── help-readFromProject.html
    │       │   ├── help-readFromProject_ja.html
    │       │   ├── help-thinning.html
    │       │   ├── help-thinning_ja.html
    │       │   ├── help-unlockKeychain.html
    │       │   ├── help-unlockKeychain_ja.html
    │       │   ├── help-uploadBitcode.html
    │       │   ├── help-uploadBitcode_ja.html
    │       │   ├── help-uploadSymbols.html
    │       │   ├── help-uploadSymbols_ja.html
    │       │   ├── help-xcodeProjectFile.html
    │       │   ├── help-xcodeProjectFile_ja.html
    │       │   ├── help-xcodeProjectPath.html
    │       │   ├── help-xcodeProjectPath_ja.html
    │       │   ├── help-xcodeSchema.html
    │       │   ├── help-xcodeSchema_ja.html
    │       │   ├── help-xcodeToolsVersion.html
    │       │   ├── help-xcodeToolsVersion_ja.html
    │       │   ├── help-xcodeWorkspaceFile.html
    │       │   └── help-xcodeWorkspaceFile_ja.html
    │       ├── help-cleanTestReports.html
    │       └── help-xcodebuildArguments.html
    └── test/
        ├── java/
        │   ├── Pkcs12.java
        │   ├── Pkcs7.java
        │   └── au/
        │       └── com/
        │           └── rayh/
        │               ├── JenkinsXCodeBuildOutputParserTest.java
        │               ├── OutputParserTests.java
        │               ├── XCodeBuildHelpParserTest.java
        │               ├── XCodeBuildListParserTest.java
        │               ├── XCodeBuildOutputParserTest.java
        │               ├── XCodeBuilderTest.java
        │               ├── XcodeProjectParserTest.java
        │               └── XcodeTestSummariesParserTest.java
        └── resources/
            ├── XCTest_output_complex_1.txt
            ├── XCTest_output_complex_2.txt
            ├── XCTest_output_crashing_1.txt
            ├── XCTest_output_failing_1.txt
            ├── XCTest_output_failing_2.txt
            ├── XCTest_output_passing_1.txt
            ├── xcodebuildhelp-invalid.txt
            ├── xcodebuildhelp-valid.txt
            ├── xcodebuildlist-invalid1.txt
            ├── xcodebuildlist-invalid2.txt
            └── xcodebuildlist-valid.txt
Download .txt
SYMBOL INDEX (591 symbols across 47 files)

FILE: src/main/java/au/com/rayh/BuildConfiguration.java
  class BuildConfiguration (line 11) | public class BuildConfiguration {
    method BuildConfiguration (line 22) | BuildConfiguration(NSDictionary objectsDict, String buildConfiguration...

FILE: src/main/java/au/com/rayh/DSymFileFilter.java
  class DSymFileFilter (line 40) | public class DSymFileFilter implements FileFilter, Serializable {
    method accept (line 42) | public boolean accept(File pathname) {

FILE: src/main/java/au/com/rayh/DeveloperProfile.java
  class DeveloperProfile (line 43) | public class DeveloperProfile extends BaseStandardCredentials {
    method DeveloperProfile (line 49) | @DataBoundConstructor
    method DeveloperProfile (line 61) | @Deprecated
    method getPassword (line 66) | public Secret getPassword() {
    method getImage (line 75) | public byte[] getImage() throws IOException {
    method getCertificates (line 85) | public @NonNull List<X509Certificate> getCertificates() throws IOExcep...
    method getDisplayNameOf (line 109) | public String getDisplayNameOf(X509Certificate p) {
    class DescriptorImpl (line 123) | @Extension
      method getDisplayName (line 125) | @Override
    class ConfidentialKeyImpl (line 131) | static class ConfidentialKeyImpl extends ConfidentialKey {
      method ConfidentialKeyImpl (line 132) | ConfidentialKeyImpl(String id) {
      method store (line 136) | public void store(FileItem submitted) throws IOException {
      method load (line 140) | public @CheckForNull byte[] load() throws IOException {
    method getAllProfiles (line 145) | public static List<DeveloperProfile> getAllProfiles() {

FILE: src/main/java/au/com/rayh/DeveloperProfileLoader.java
  class DeveloperProfileLoader (line 59) | @SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
    method getProfileId (line 74) | @CheckForNull
    method setProfileId (line 79) | @DataBoundSetter
    method getImportIntoExistingKeychain (line 84) | public Boolean getImportIntoExistingKeychain() {
    method setImportIntoExistingKeychain (line 88) | @DataBoundSetter
    method getKeychainId (line 93) | @CheckForNull
    method getKeychainName (line 98) | @Deprecated
    method setKeychainId (line 104) | @DataBoundSetter
    method setKeychainName (line 109) | @Deprecated
    method getKeychainPath (line 115) | @CheckForNull
    method setKeychainPath (line 120) | @DataBoundSetter
    method getKeychainPwd (line 125) | @CheckForNull
    method setKeychainPwd (line 130) | @DataBoundSetter
    method DeveloperProfileLoader (line 135) | @DataBoundConstructor
    method DeveloperProfileLoader (line 139) | @Deprecated
    method perform (line 145) | @Override
    method perform (line 294) | @Override
    method getDescriptor (line 301) | @Override
    method getGlobalConfiguration (line 306) | public GlobalConfigurationImpl getGlobalConfiguration() {
    method getKeychain (line 310) | public Keychain getKeychain(String keychainName) {
    method getKeychainPasswordAndPath (line 328) | public KeychainPasswordAndPath getKeychainPasswordAndPath(Item context...
    method importAppleCert (line 335) | public void importAppleCert(Launcher launcher, TaskListener listener, ...
    method invoke (line 348) | private ByteArrayOutputStream invoke(Launcher launcher, TaskListener l...
    method getSecretDir (line 357) | private FilePath getSecretDir(FilePath workspace, String keychainPwd) ...
    method getProfile (line 364) | public DeveloperProfile getProfile(Item context, String profileId) {
    class DescriptorImpl (line 371) | @Extension
      method setGlobalConfiguration (line 376) | @SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
      method isApplicable (line 382) | @Override
      method getDisplayName (line 387) | @Override
      method doFillProfileIdItems (line 392) | public ListBoxModel doFillProfileIdItems(@AncestorInPath Item contex...
      method getGlobalConfiguration (line 402) | public GlobalConfigurationImpl getGlobalConfiguration() {
      method getUUID (line 406) | public String getUUID() {
      method doCheckDeveloperProfileId (line 410) | public FormValidation doCheckDeveloperProfileId(@QueryParameter Stri...
      method doCheckKeychainPath (line 417) | public FormValidation doCheckKeychainPath(@QueryParameter String val...
      method doCheckKeychainPwd (line 426) | public FormValidation doCheckKeychainPwd(@QueryParameter Secret valu...
    class GetHomeDirectory (line 436) | private static final class GetHomeDirectory extends MasterToSlaveCalla...
      method call (line 437) | public FilePath call() throws IOException {
      method checkRoles (line 441) | @Override

FILE: src/main/java/au/com/rayh/ExportIpa.java
  class ExportIpa (line 29) | public class ExportIpa extends Builder implements SimpleBuildStep {
    method getXcodeProjectPath (line 111) | @CheckForNull
    method setXcodeProjectPath (line 116) | @DataBoundSetter
    method getXcodeProjectFile (line 121) | @CheckForNull
    method getUnlockKeychain (line 126) | public Boolean getUnlockKeychain() {
    method setUnlockKeychain (line 130) | @DataBoundSetter
    method getKeychainName (line 135) | @CheckForNull
    method setKeychainName (line 140) | @DataBoundSetter
    method getKeychainPath (line 145) | @CheckForNull
    method setKeychainPath (line 150) | @DataBoundSetter
    method getKeychainPwd (line 155) | @CheckForNull
    method setKeychainPwd (line 160) | @DataBoundSetter
    method getSymRoot (line 165) | @CheckForNull
    method setSymRoot (line 170) | @DataBoundSetter
    method getXcodeWorkspaceFile (line 175) | @CheckForNull
    method setXcodeWorkspaceFile (line 180) | @DataBoundSetter
    method getXcodeSchema (line 185) | @CheckForNull
    method setXcodeSchema (line 190) | @DataBoundSetter
    method getArchiveDir (line 195) | @CheckForNull
    method setArchiveDir (line 200) | @DataBoundSetter
    method getDevelopmentTeamName (line 205) | @CheckForNull
    method setDevelopmentTeamName (line 210) | @DataBoundSetter
    method getDevelopmentTeamID (line 215) | @CheckForNull
    method setDevelopmentTeamID (line 220) | @DataBoundSetter
    method getIpaName (line 225) | @CheckForNull
    method setIpaName (line 230) | @DataBoundSetter
    method getIpaOutputDirectory (line 235) | @CheckForNull
    method setIpaOutputDirectory (line 240) | @DataBoundSetter
    method getIpaExportMethod (line 245) | @CheckForNull
    method setIpaExportMethod (line 250) | @DataBoundSetter
    method getManualSigning (line 255) | @Deprecated
    method setManualSigning (line 260) | @Deprecated
    method getSigningMethod (line 266) | @CheckForNull
    method setSigningMethod (line 271) | @DataBoundSetter
    method getProvisioningProfiles (line 276) | @CheckForNull
    method setProvisioningProfiles (line 281) | @DataBoundSetter
    method getXcodeName (line 286) | @CheckForNull
    method setXcodeName (line 291) | @DataBoundSetter
    method getUploadBitcode (line 296) | public Boolean getUploadBitcode() {
    method setUploadBitcode (line 300) | @DataBoundSetter
    method getUploadSymbols (line 305) | public Boolean getUploadSymbols() {
    method setUploadSymbols (line 309) | @DataBoundSetter
    method getCompileBitcode (line 314) | public Boolean getCompileBitcode() {
    method setCompileBitcode (line 318) | @DataBoundSetter
    method getThinning (line 323) | @CheckForNull
    method setThinning (line 328) | @DataBoundSetter
    method getPackResourcesAsset (line 333) | public Boolean getPackResourcesAsset() {
    method setPackResourcesAsset (line 337) | @DataBoundSetter
    method getResourcesAssetURL (line 342) | @CheckForNull
    method setResourcesAssetURL (line 347) | @DataBoundSetter
    method getAppURL (line 352) | @CheckForNull
    method setAppURL (line 357) | @DataBoundSetter
    method getDisplayImageURL (line 362) | @CheckForNull
    method setDisplayImageURL (line 367) | @DataBoundSetter
    method getFullSizeImageURL (line 372) | @CheckForNull
    method setFullSizeImageURL (line 377) | @DataBoundSetter
    method getAssetPackManifestURL (line 382) | @CheckForNull
    method setAssetPackManifestURL (line 387) | @DataBoundSetter
    method getStripSwiftSymbols (line 392) | public Boolean getStripSwiftSymbols() {
    method setStripSwiftSymbols (line 396) | @DataBoundSetter
    method getCopyProvisioningProfile (line 401) | public Boolean getCopyProvisioningProfile() {
    method setCopyProvisioningProfile (line 405) | @DataBoundSetter
    method getKeychainId (line 410) | @CheckForNull
    method setKeychainId (line 415) | @DataBoundSetter
    method ExportIpa (line 420) | @DataBoundConstructor
    method ExportIpa (line 424) | @Deprecated
    method perform (line 467) | @Override
    method _perform (line 472) | @SuppressFBWarnings("DM_DEFAULT_ENCODING")
    method getGlobalConfiguration (line 493) | public GlobalConfigurationImpl getGlobalConfiguration() {
    method getDescriptor (line 497) | @Override
    class DescriptorImpl (line 502) | @Extension
      method getDisplayName (line 507) | @Override
      method DescriptorImpl (line 512) | public DescriptorImpl() {
      method setGlobalConfiguration (line 516) | @SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
      method getGlobalConfiguration (line 522) | public GlobalConfigurationImpl getGlobalConfiguration() {
      method isApplicable (line 526) | @Override
      method getUUID (line 531) | public String getUUID() {
      method doCheckArchiveDir (line 535) | public FormValidation doCheckArchiveDir(@QueryParameter String value) {
      method doCheckResourcesAssetURL (line 542) | public FormValidation doCheckResourcesAssetURL(@QueryParameter Strin...
      method doCheckIpaExportMethod (line 549) | public FormValidation doCheckIpaExportMethod(@QueryParameter String ...
      method doCheckXcodeWorkspaceFile (line 557) | public FormValidation doCheckXcodeWorkspaceFile(@QueryParameter Stri...
      method doCheckXcodeSchema (line 569) | public FormValidation doCheckXcodeSchema(@QueryParameter String valu...

FILE: src/main/java/au/com/rayh/GlobalConfigurationImpl.java
  class GlobalConfigurationImpl (line 52) | @Extension
    method setXcodebuildPath (line 72) | @DataBoundSetter
    method getXcodebuildPath (line 77) | @CheckForNull
    method setXcrunPath (line 82) | @DataBoundSetter
    method getXcrunPath (line 87) | @CheckForNull
    method setAgvtoolPath (line 92) | @DataBoundSetter
    method getAgvtoolPath (line 97) | @CheckForNull
    method setDefaultKeychain (line 102) | @Deprecated
    method getDefaultKeychain (line 108) | @Deprecated
    method setKeychains (line 114) | @Deprecated
    method getKeychains (line 120) | @Deprecated
    method setTeams (line 125) | @Deprecated
    method getTeams (line 131) | @Deprecated
    method GlobalConfigurationImpl (line 136) | @DataBoundConstructor
    method GlobalConfigurationImpl (line 143) | @Deprecated
    method GlobalConfigurationImpl (line 160) | @Deprecated
    method doCheckXcodebuildPath (line 165) | public FormValidation doCheckXcodebuildPath(@QueryParameter String val...
    method doCheckAgvtoolPath (line 174) | public FormValidation doCheckAgvtoolPath(@QueryParameter String value)...
    method doCheckXcrunPath (line 183) | public FormValidation doCheckXcrunPath(@QueryParameter String value) t...
    method doAutoCompleteDefaultKeychain (line 212) | public AutoCompletionCandidates doAutoCompleteDefaultKeychain(@QueryPa...
    method isApplicable (line 222) | public boolean isApplicable(Class<? extends AbstractProject> aClass) {
    method getDisplayName (line 227) | @Override
    method configure (line 232) | @Override

FILE: src/main/java/au/com/rayh/InfoPlist.java
  class InfoPlist (line 7) | public class InfoPlist {
    method InfoPlist (line 14) | InfoPlist() {
    method InfoPlist (line 22) | InfoPlist(FilePath infoPlistFile, String cfBundleIdentifier, String cf...
    method getInfoPlistFile (line 29) | public FilePath getInfoPlistFile() {
    method setInfoPlistFile (line 33) | public void setInfoPlistFile(FilePath infoPlistFile) {
    method getCfBundleIdentifier (line 37) | public String getCfBundleIdentifier() {
    method setCfBundleIdentifier (line 41) | public void setCfBundleIdentifier(String cfBundleIdentifier) {
    method getCfBundleVersion (line 45) | public String getCfBundleVersion() {
    method setCfBundleVersion (line 49) | public void setCfBundleVersion(String cfBundleVersion) {
    method getCfBundleShortVersionString (line 53) | public String getCfBundleShortVersionString() {
    method setCfBundleShortVersionString (line 57) | public void setCfBundleShortVersionString(String cfBundleShortVersionS...

FILE: src/main/java/au/com/rayh/JenkinsXCodeBuildOutputParser.java
  class JenkinsXCodeBuildOutputParser (line 49) | public class JenkinsXCodeBuildOutputParser extends XCodeBuildOutputParser {
    method JenkinsXCodeBuildOutputParser (line 55) | public JenkinsXCodeBuildOutputParser(FilePath workspace, TaskListener ...
    method setConsoleLog (line 67) | public void setConsoleLog(boolean consoleLog) {
    method setIgnoreTestResults (line 71) | public void setIgnoreTestResults(boolean ignoreTestResults) {
    method setLogfilePath (line 75) | public void setLogfilePath(final FilePath buildDirectory, final String...
    method closeLogfile (line 94) | public void closeLogfile() throws IOException {
    class LineBasedFilterOutputStream (line 102) | public class LineBasedFilterOutputStream extends FilterOutputStream {
      method LineBasedFilterOutputStream (line 105) | public LineBasedFilterOutputStream() {
      method write (line 109) | @Override
      method close (line 132) | @Override
    method outputForSuite (line 143) | @Override

FILE: src/main/java/au/com/rayh/Keychain.java
  class Keychain (line 8) | public class Keychain {
    method Keychain (line 14) | public Keychain() {
    method Keychain (line 17) | @Deprecated
    method getKeychainName (line 26) | public String getKeychainName() {
    method setKeychainName (line 30) | @DataBoundSetter
    method getKeychainPath (line 35) | public String getKeychainPath() {
    method setKeychainPath (line 39) | @DataBoundSetter
    method getKeychainPassword (line 44) | public Secret getKeychainPassword() {
    method setKeychainPassword (line 48) | @DataBoundSetter
    method isInSearchPath (line 53) | public Boolean isInSearchPath() {
    method setInSearchPath (line 57) | @DataBoundSetter

FILE: src/main/java/au/com/rayh/KeychainPasswordAndPath.java
  type KeychainPasswordAndPath (line 40) | @NameWith(value = KeychainPasswordAndPath.NameProvider.class, priority =...
    method getPassword (line 46) | Secret getPassword();
    method getKeychainPath (line 47) | String getKeychainPath();
    method isInSearchPath (line 48) | boolean isInSearchPath();
    method getInSearchPath (line 49) | String getInSearchPath();
    class NameProvider (line 56) | public static class NameProvider extends CredentialsNameProvider<Keych...
      method getName (line 61) | @NonNull

FILE: src/main/java/au/com/rayh/KeychainPasswordAndPathBinding.java
  class KeychainPasswordAndPathBinding (line 51) | public class KeychainPasswordAndPathBinding extends MultiBinding<Keychai...
    method KeychainPasswordAndPathBinding (line 71) | @DataBoundConstructor
    method getKeychainPathVariable (line 79) | @NonNull
    method getPasswordVariable (line 84) | @NonNull
    method getInSearchPathVariable (line 89) | @NonNull
    method type (line 94) | @Override
    method bind (line 99) | @Override
    method variables (line 109) | @Override
    class DescriptorImpl (line 114) | @Extension
      method type (line 117) | @Override protected Class<KeychainPasswordAndPath> type() {
      method getDisplayName (line 121) | @Override public String getDisplayName() {

FILE: src/main/java/au/com/rayh/KeychainPasswordAndPathImpl.java
  class KeychainPasswordAndPathImpl (line 46) | @SuppressWarnings("unused") // read resolved by extension plugins
    method KeychainPasswordAndPathImpl (line 76) | @DataBoundConstructor
    method getPassword (line 93) | public Secret getPassword() {
    method setPassword (line 97) | @DataBoundSetter
    method getKeychainPath (line 106) | @NonNull
    method setKeychainPath (line 111) | @DataBoundSetter
    method getInSearchPath (line 120) | public String getInSearchPath() {
    method setInSearchPath (line 124) | @DataBoundSetter
    method isInSearchPath (line 133) | public boolean isInSearchPath() {
    class DescriptorImpl (line 140) | @Extension
      method getDisplayName (line 146) | @Override
    method getAllKeycainInfo (line 161) | public static List<KeychainPasswordAndPathImpl> getAllKeycainInfo() {

FILE: src/main/java/au/com/rayh/KeychainUnlockStep.java
  class KeychainUnlockStep (line 43) | @SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
    method getKeychainName (line 55) | @Deprecated
    method getKeychainId (line 61) | @CheckForNull
    method setKeychainName (line 66) | @Deprecated
    method setKeychainId (line 72) | @DataBoundSetter
    method getKeychainPath (line 77) | @CheckForNull
    method setKeychainPath (line 82) | @DataBoundSetter
    method getKeychainPwd (line 87) | @CheckForNull
    method setKeychainPwd (line 92) | @DataBoundSetter
    method KeychainUnlockStep (line 97) | @DataBoundConstructor
    method KeychainUnlockStep (line 101) | @Deprecated
    method perform (line 107) | @Override
    method perform (line 151) | @Override
    method getDescriptor (line 158) | @Override
    method getGlobalConfiguration (line 163) | public GlobalConfigurationImpl getGlobalConfiguration() {
    method getKeychain (line 167) | public Keychain getKeychain(String keychainName) {
    method getKeychainPasswordAndPath (line 185) | public KeychainPasswordAndPath getKeychainPasswordAndPath(Item context...
    method invoke (line 192) | private ByteArrayOutputStream invoke(Launcher launcher, TaskListener l...
    class DescriptorImpl (line 201) | @Extension
      method setGlobalConfiguration (line 206) | @SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
      method isApplicable (line 212) | @Override
      method getDisplayName (line 217) | @Override
      method getGlobalConfiguration (line 222) | public GlobalConfigurationImpl getGlobalConfiguration() {
      method getUUID (line 226) | public String getUUID() {
      method doCheckKeychainPath (line 230) | public FormValidation doCheckKeychainPath(@QueryParameter String val...
      method doCheckKeychainPwd (line 237) | public FormValidation doCheckKeychainPwd(@QueryParameter Secret valu...

FILE: src/main/java/au/com/rayh/MobileProvisionParser.java
  class MobileProvisionParser (line 11) | public class MobileProvisionParser {
    method MobileProvisionParser (line 17) | public MobileProvisionParser(String xcodebuildListOutput) {
    method getTargets (line 41) | public List<String> getTargets() {
    method getConfigurations (line 45) | public List<String> getConfigurations() {
    method getSchemes (line 49) | public List<String> getSchemes() {

FILE: src/main/java/au/com/rayh/ProjectScheme.java
  class ProjectScheme (line 3) | public class ProjectScheme {
    method ProjectScheme (line 17) | ProjectScheme() {

FILE: src/main/java/au/com/rayh/ProjectTarget.java
  class ProjectTarget (line 5) | public class ProjectTarget {
    method ProjectTarget (line 14) | ProjectTarget() {

FILE: src/main/java/au/com/rayh/ProvisioningProfile.java
  class ProvisioningProfile (line 6) | public class ProvisioningProfile {
    method ProvisioningProfile (line 13) | public ProvisioningProfile() {
    method ProvisioningProfile (line 16) | @DataBoundConstructor
    method getProvisioningProfileAppId (line 22) | public String getProvisioningProfileAppId() {
    method setProvisioningProfileAppId (line 26) | public void setProvisioningProfileAppId(String provisioningProfileAppI...
    method getProvisioningProfileUUID (line 30) | public String getProvisioningProfileUUID() {
    method setProvisioningProfileUUID (line 34) | public void setProvisioningProfileUUID(String provisioningProfileUUID) {
    method toPlist (line 38) | public String toPlist(EnvVars envs) {

FILE: src/main/java/au/com/rayh/Team.java
  class Team (line 5) | public class Team {
    method Team (line 10) | public Team() {
    method Team (line 13) | @DataBoundConstructor
    method getTeamName (line 19) | public String getTeamName() {
    method setTeamName (line 23) | public void setTeamName(String teamName) {
    method getTeamID (line 27) | public String getTeamID() {
    method setTeamID (line 31) | public void setTeamID(String teamID) {

FILE: src/main/java/au/com/rayh/XCArchiveFileFilter.java
  class XCArchiveFileFilter (line 39) | public class XCArchiveFileFilter implements FileFilter, Serializable {
    method accept (line 41) | public boolean accept(File pathname) {

FILE: src/main/java/au/com/rayh/XCodeAction.java
  class XCodeAction (line 10) | public class XCodeAction extends InvisibleAction {
    method XCodeAction (line 13) | @DataBoundConstructor
    method getBuildDescription (line 18) | public  String getBuildDescription() { return buildDescription; }

FILE: src/main/java/au/com/rayh/XCodeBuildNumberTokenMacro.java
  class XCodeBuildNumberTokenMacro (line 12) | @Extension
    method evaluate (line 14) | @Override
    method acceptsMacroName (line 24) | @Override

FILE: src/main/java/au/com/rayh/XCodeBuildOutputParser.java
  class XCodeBuildOutputParser (line 57) | public class XCodeBuildOutputParser {
    method XCodeBuildOutputParser (line 80) | protected XCodeBuildOutputParser() {
    method XCodeBuildOutputParser (line 89) | public XCodeBuildOutputParser(File workspace, OutputStream log) {
    class LineBasedFilterOutputStream (line 96) | public class LineBasedFilterOutputStream extends FilterOutputStream {
      method LineBasedFilterOutputStream (line 99) | public LineBasedFilterOutputStream(OutputStream log) {
      method write (line 103) | @Override
    method parseDate (line 119) | private Date parseDate(String text) throws ParseException {
    method requireTestSuite (line 142) | private void requireTestSuite() {
    method requireTestSuite (line 151) | private void requireTestSuite(String name) {
    method requireTestCase (line 170) | private void requireTestCase(String name) {
    method writeTestReport (line 177) | private void writeTestReport() throws IOException, InterruptedException,
    method outputForSuite (line 194) | protected OutputStream outputForSuite() throws IOException,
    method handleLine (line 199) | protected void handleLine(String line) throws ParseException, IOExcept...
    method getOutputStream (line 348) | public OutputStream getOutputStream() {
    method getExitCode (line 352) | public int getExitCode() {

FILE: src/main/java/au/com/rayh/XCodeBuilder.java
  class XCodeBuilder (line 81) | @SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
    method getCleanBeforeBuild (line 375) | public Boolean getCleanBeforeBuild() {
    method setCleanBeforeBuild (line 379) | @DataBoundSetter
    method getCleanTestReports (line 384) | public Boolean getCleanTestReports() {
    method setCleanTestReports (line 388) | @DataBoundSetter
    method getConfiguration (line 393) | @CheckForNull
    method setConfiguration (line 398) | @DataBoundSetter
    method getTarget (line 403) | @CheckForNull
    method setTarget (line 408) | @DataBoundSetter
    method getSdk (line 413) | @CheckForNull
    method setSdk (line 418) | @DataBoundSetter
    method getSymRoot (line 423) | @CheckForNull
    method setSymRoot (line 428) | @DataBoundSetter
    method getBuildDir (line 433) | @CheckForNull
    method setBuildDir (line 438) | @DataBoundSetter
    method getXcodeProjectPath (line 443) | @CheckForNull
    method setXcodeProjectPath (line 448) | @DataBoundSetter
    method getXcodeProjectFile (line 453) | @CheckForNull
    method setXcodeProjectFile (line 458) | @DataBoundSetter
    method getXcodebuildArguments (line 463) | @CheckForNull
    method setXcodebuildArguments (line 468) | @DataBoundSetter
    method getXcodeSchema (line 473) | @CheckForNull
    method setXcodeSchema (line 478) | @DataBoundSetter
    method getXcodeWorkspaceFile (line 483) | @CheckForNull
    method setXcodeWorkspaceFile (line 488) | @DataBoundSetter
    method getCfBundleVersionValue (line 493) | @CheckForNull
    method setCfBundleVersionValue (line 498) | @DataBoundSetter
    method getCfBundleShortVersionStringValue (line 503) | @CheckForNull
    method setCfBundleShortVersionStringValue (line 508) | @DataBoundSetter
    method getBuildIpa (line 513) | public Boolean getBuildIpa() {
    method setBuildIpa (line 517) | @DataBoundSetter
    method getIpaExportMethod (line 522) | public String getIpaExportMethod() {
    method setIpaExportMethod (line 526) | @DataBoundSetter
    method getGenerateArchive (line 531) | public Boolean getGenerateArchive() {
    method setGenerateArchive (line 535) | @DataBoundSetter
    method getNoConsoleLog (line 540) | public Boolean getNoConsoleLog() {
    method setNoConsoleLog (line 544) | @DataBoundSetter
    method getLogfileOutputDirectory (line 549) | @CheckForNull
    method setLogfileOutputDirectory (line 554) | @DataBoundSetter
    method getUnlockKeychain (line 559) | public Boolean getUnlockKeychain() {
    method setUnlockKeychain (line 563) | @DataBoundSetter
    method getKeychainName (line 568) | @Deprecated
    method getKeychainId (line 574) | @CheckForNull
    method setKeychainName (line 579) | @Deprecated
    method setKeychainId (line 585) | @DataBoundSetter
    method getKeychainPath (line 590) | @CheckForNull
    method setKeychainPath (line 595) | @DataBoundSetter
    method getKeychainPwd (line 600) | @CheckForNull
    method setKeychainPwd (line 605) | @DataBoundSetter
    method getDevelopmentTeamName (line 610) | @CheckForNull
    method setDevelopmentTeamName (line 615) | @DataBoundSetter
    method getDevelopmentTeamID (line 620) | @CheckForNull
    method setDevelopmentTeamID (line 625) | @DataBoundSetter
    method getAllowFailingBuildResults (line 630) | public Boolean getAllowFailingBuildResults() {
    method setAllowFailingBuildResults (line 634) | @DataBoundSetter
    method getIpaName (line 639) | @CheckForNull
    method setIpaName (line 644) | @DataBoundSetter
    method getIpaOutputDirectory (line 649) | @CheckForNull
    method setIpaOutputDirectory (line 654) | @DataBoundSetter
    method getProvideApplicationVersion (line 659) | public Boolean getProvideApplicationVersion() {
    method setProvideApplicationVersion (line 663) | @DataBoundSetter
    method getChangeBundleID (line 668) | public Boolean getChangeBundleID() {
    method setChangeBundleID (line 672) | @DataBoundSetter
    method getBundleID (line 677) | @CheckForNull
    method setBundleID (line 682) | @DataBoundSetter
    method getBundleIDInfoPlistPath (line 687) | @CheckForNull
    method setBundleIDInfoPlistPath (line 692) | @DataBoundSetter
    method getInterpretTargetAsRegEx (line 697) | public Boolean getInterpretTargetAsRegEx() {
    method setInterpretTargetAsRegEx (line 701) | @DataBoundSetter
    method getManualSigning (line 706) | @Deprecated
    method setManualSigning (line 711) | @Deprecated
    method getSigningMethod (line 717) | public String getSigningMethod() {
    method setSigningMethod (line 721) | @DataBoundSetter
    method getProvisioningProfiles (line 726) | @CheckForNull
    method setProvisioningProfiles (line 731) | @DataBoundSetter
    method getXcodeName (line 736) | @CheckForNull
    method setXcodeName (line 741) | @DataBoundSetter
    method getUploadBitcode (line 746) | public Boolean getUploadBitcode() {
    method setUploadBitcode (line 750) | @DataBoundSetter
    method getUploadSymbols (line 755) | public Boolean getUploadSymbols() {
    method setUploadSymbols (line 759) | @DataBoundSetter
    method getCompileBitcode (line 764) | public Boolean getCompileBitcode() {
    method setCompileBitcode (line 768) | @DataBoundSetter
    method getThinning (line 773) | @CheckForNull
    method setThinning (line 778) | @DataBoundSetter
    method getAssetPacksInBundle (line 783) | public Boolean getAssetPacksInBundle() {
    method setAssetPacksInBundle (line 787) | @DataBoundSetter
    method getAssetPacksBaseURL (line 792) | @CheckForNull
    method setAssetPacksBaseURL (line 797) | @DataBoundSetter
    method getAppURL (line 802) | @CheckForNull
    method setAppURL (line 807) | @DataBoundSetter
    method getDisplayImageURL (line 812) | @CheckForNull
    method setDisplayImageURL (line 817) | @DataBoundSetter
    method getFullSizeImageURL (line 822) | @CheckForNull
    method setFullSizeImageURL (line 827) | @DataBoundSetter
    method getAssetPackManifestURL (line 832) | @CheckForNull
    method setAssetPackManifestURL (line 837) | @DataBoundSetter
    method getStripSwiftSymbols (line 842) | public Boolean getStripSwiftSymbols() {
    method setStripSwiftSymbols (line 846) | @DataBoundSetter
    method getCopyProvisioningProfile (line 851) | public Boolean getCopyProvisioningProfile() {
    method setCopyProvisioningProfile (line 855) | @DataBoundSetter
    method getUseLegacyBuildSystem (line 860) | public Boolean getUseLegacyBuildSystem() {
    method setUseLegacyBuildSystem (line 864) | @DataBoundSetter
    method getIgnoreTestResults (line 869) | public Boolean getIgnoreTestResults() {
    method setIgnoreTestResults (line 873) | @DataBoundSetter
    method getResultBundlePath (line 878) | public String getResultBundlePath() {
    method setResultBundlePath (line 882) | @DataBoundSetter
    method setCleanResultBundlePath (line 887) | @DataBoundSetter
    method getCleanResultBundlePath (line 892) | public Boolean getCleanResultBundlePath() {
    method setSkipBuildStep (line 897) | public void setSkipBuildStep(Boolean skipBuildStep) {
    method XCodeBuilder (line 902) | @DataBoundConstructor
    method XCodeBuilder (line 907) | @Deprecated
    method XCodeBuilder (line 975) | @Deprecated
    method XCodeBuilder (line 995) | @Deprecated
    method XCodeBuilder (line 1014) | @Deprecated
    method XCodeBuilder (line 1032) | @Deprecated
    method XCodeBuilder (line 1050) | @Deprecated
    method readResolve (line 1068) | @SuppressWarnings("unused")
    method perform (line 1079) | @Override
    method perform (line 1087) | @Override
    method _perform (line 1092) | @SuppressFBWarnings("DM_DEFAULT_ENCODING")
    method getKeychain (line 2115) | @Deprecated
    method getKeychainPasswordAndPath (line 2126) | public KeychainPasswordAndPath getKeychainPasswordAndPath(Item context...
    method getDevelopmentTeam (line 2136) | public Team getDevelopmentTeam() {
    method splitXcodeBuildArguments (line 2151) | static List<String> splitXcodeBuildArguments(String xcodebuildArgument...
    method getGlobalConfiguration (line 2164) | public GlobalConfigurationImpl getGlobalConfiguration() {
    method getDescriptor (line 2168) | @Override
    class DescriptorImpl (line 2173) | @Extension
      method DescriptorImpl (line 2186) | public DescriptorImpl() {
      method setGlobalConfiguration (line 2190) | @SuppressFBWarnings("UWF_UNWRITTEN_FIELD")
      method isApplicable (line 2223) | @Override
      method getDisplayName (line 2228) | @Override
      method getGlobalConfiguration (line 2233) | public GlobalConfigurationImpl getGlobalConfiguration() {
      method getUUID (line 2237) | public String getUUID() {
      method doCheckOnDemandResourcesAssetPacksBaseURL (line 2241) | public FormValidation doCheckOnDemandResourcesAssetPacksBaseURL(@Que...
      method doCheckIpaExportMethod (line 2248) | public FormValidation doCheckIpaExportMethod(@QueryParameter String ...
      method doCheckXcodeWorkspaceFile (line 2258) | public FormValidation doCheckXcodeWorkspaceFile(@QueryParameter Stri...
      method doCheckXcodeSchema (line 2270) | public FormValidation doCheckXcodeSchema(@QueryParameter String valu...
      method doCheckTarget (line 2287) | public FormValidation doCheckTarget(@QueryParameter String value, @Q...

FILE: src/main/java/au/com/rayh/XcodeBuildHelpParser.java
  class XcodeBuildHelpParser (line 10) | public class XcodeBuildHelpParser {
    method XcodeBuildHelpParser (line 14) | public XcodeBuildHelpParser(String xcodebuildHelpOutput) {
    method getParameters (line 31) | public List<String> getParameters() {

FILE: src/main/java/au/com/rayh/XcodeBuildListParser.java
  class XcodeBuildListParser (line 11) | public class XcodeBuildListParser {
    method XcodeBuildListParser (line 17) | public XcodeBuildListParser(String xcodebuildListOutput) {
    method getTargets (line 41) | public List<String> getTargets() {
    method getConfigurations (line 45) | public List<String> getConfigurations() {
    method getSchemes (line 49) | public List<String> getSchemes() {

FILE: src/main/java/au/com/rayh/XcodeCredentialsHelper.java
  class XcodeCredentialsHelper (line 17) | public class XcodeCredentialsHelper {
    method XcodeCredentialsHelper (line 19) | private XcodeCredentialsHelper() {}
    method getCredentials (line 21) | @CheckForNull
    method doFillCredentialsIdItems (line 32) | public static ListBoxModel doFillCredentialsIdItems(ItemGroup context) {

FILE: src/main/java/au/com/rayh/XcodeDeclarativeCredentialsHandler.java
  class XcodeDeclarativeCredentialsHandler (line 37) | @Extension
    method type (line 40) | @NonNull
    method getWithCredentialsParameters (line 46) | @NonNull

FILE: src/main/java/au/com/rayh/XcodeProject.java
  class XcodeProject (line 6) | public class XcodeProject {
    method XcodeProject (line 13) | XcodeProject() {

FILE: src/main/java/au/com/rayh/XcodeProjectFileFilter.java
  class XcodeProjectFileFilter (line 39) | public class XcodeProjectFileFilter implements FileFilter, Serializable {
    method accept (line 41) | public boolean accept(File pathname) {

FILE: src/main/java/au/com/rayh/XcodeProjectParser.java
  class XcodeProjectParser (line 40) | public class XcodeProjectParser {
    method listXcodeSchemes (line 47) | public static HashMap<String, ProjectScheme> listXcodeSchemes(FilePath...
    method parseXcodeScheme (line 92) | public static ProjectScheme parseXcodeScheme(FilePath schemeFile) {
    method parseXcodeWorkspace (line 187) | public static List<String> parseXcodeWorkspace(FilePath workspaceFileL...
    method parseInfoPlist (line 250) | public static InfoPlist parseInfoPlist(FilePath infoPlistFile) {
    method parseXcodeProject (line 269) | public static XcodeProject parseXcodeProject(FilePath projectLocation) {

FILE: src/main/java/au/com/rayh/XcodeSchemeFileFilter.java
  class XcodeSchemeFileFilter (line 39) | public class XcodeSchemeFileFilter implements FileFilter, Serializable {
    method accept (line 41) | public boolean accept(File pathname) {

FILE: src/main/java/au/com/rayh/XcodeTestSummariesParser.java
  class XcodeTestSummariesParser (line 30) | public class XcodeTestSummariesParser {
    method XcodeTestSummariesParser (line 35) | public XcodeTestSummariesParser(FilePath workspace) throws IOException...
    method writeTestReport (line 41) | private void writeTestReport(TestSuite currentTestSuite) throws IOExce...
    method outputForSuite (line 58) | protected OutputStream outputForSuite(TestSuite currentTestSuite) thro...
    method addFailureSummaries (line 62) | private static void addFailureSummaries(NSObject[] failureSummaries, T...
    method parseSubTests (line 108) | public void parseSubTests(NSObject[] tests, TestSuite parentTestSuite)...
    method parseTestSummariesPlist (line 155) | public void parseTestSummariesPlist(FilePath testSummariesPlistFile) {

FILE: src/main/java/au/com/rayh/report/TestCase.java
  class TestCase (line 37) | @XmlType(name="testcase")
    method TestCase (line 55) | public TestCase() {
    method TestCase (line 58) | @SuppressFBWarnings("URF_UNREAD_FIELD")
    method getName (line 64) | public String getName() {
    method setTime (line 68) | public void setTime(float time) {
    method getTime (line 72) | public float getTime() {
    method getFailures (line 76) | public List<TestFailure> getFailures() {
    method getErrors (line 80) | public List<TestError> getErrors() {

FILE: src/main/java/au/com/rayh/report/TestError.java
  class TestError (line 32) | @XmlType(name="error")
    method TestError (line 41) | public TestError() {
    method TestError (line 44) | public TestError(String message, String type) {
    method getMessage (line 49) | public String getMessage() {
    method getType (line 53) | public String getType() {

FILE: src/main/java/au/com/rayh/report/TestFailure.java
  class TestFailure (line 35) | @XmlType(name="failure")
    method TestFailure (line 48) | public TestFailure() {
    method TestFailure (line 51) | public TestFailure(String message, String location) {
    method getMessage (line 56) | public String getMessage() {
    method getLocation (line 60) | public String getLocation() {

FILE: src/main/java/au/com/rayh/report/TestSuite.java
  class TestSuite (line 40) | @XmlRootElement(name="testsuite")
    method TestSuite (line 72) | public TestSuite() {
    method TestSuite (line 75) | @SuppressFBWarnings({"EI_EXPOSE_REP2", "URF_UNREAD_FIELD"})
    method setDuration (line 82) | public void setDuration(Float duration) {
    method getTestCasesHash (line 86) | public HashMap<String, TestCase> getTestCasesHash() {
    method setTestCasesHash (line 90) | public void setTestCasesHash(HashMap<String, TestCase> testCasesHash) {
    method getFailures (line 94) | public int getFailures() {
    method getErrors (line 98) | public int getErrors() {
    method getTests (line 102) | public int getTests() {
    method addFailure (line 106) | public void addFailure() {
    method addError (line 110) | public void addError() {
    method addTest (line 114) | public void addTest() {
    method getName (line 118) | public String getName() {
    method getStartTime (line 122) | @SuppressFBWarnings("EI_EXPOSE_REP")
    method setEndTime (line 127) | @SuppressFBWarnings({"EI_EXPOSE_REP2", "URF_UNREAD_FIELD"})
    method getTestCases (line 133) | public List<TestCase> getTestCases() {

FILE: src/main/java/hudson/plugins/xcode/XcodeInstallation.java
  class XcodeInstallation (line 36) | public class XcodeInstallation extends ToolInstallation implements NodeS...
    method XcodeInstallation (line 45) | @DataBoundConstructor
    method allInstallations (line 50) | public static XcodeInstallation[] allInstallations() {
    method getXcodebuild (line 69) | public String getXcodebuild() {
    method getInstallations (line 73) | private static XcodeInstallation[] getInstallations(DescriptorImpl des...
    method forNode (line 83) | public XcodeInstallation forNode(Node node, TaskListener log) throws I...
    method forEnvironment (line 87) | public XcodeInstallation forEnvironment(EnvVars environment) {
    method getDescriptor (line 91) | @Override
    class DescriptorImpl (line 101) | @Extension @Symbol("xcode")
      method DescriptorImpl (line 104) | public DescriptorImpl() {
      method getDisplayName (line 108) | @Override
      method configure (line 113) | @Override
      method doCheckHome (line 120) | public FormValidation doCheckHome(@QueryParameter File value) {
      method getInstallation (line 127) | public XcodeInstallation getInstallation(String name) {

FILE: src/test/java/Pkcs12.java
  class Pkcs12 (line 15) | public class Pkcs12 {
    method main (line 16) | public static void main(String[] args) throws Exception {
    method getCanonicalName (line 32) | private static String getCanonicalName(X500Principal p) throws Invalid...

FILE: src/test/java/Pkcs7.java
  class Pkcs7 (line 10) | public class Pkcs7 {
    method main (line 11) | public static void main(String[] args) throws Exception {

FILE: src/test/java/au/com/rayh/JenkinsXCodeBuildOutputParserTest.java
  class JenkinsXCodeBuildOutputParserTest (line 50) | public class JenkinsXCodeBuildOutputParserTest {
    method setUp (line 53) | @Before
    method tearDown (line 92) | @After
    method shouldIgnoreStartSuiteLineThatContainsFullPath (line 96) | @Test
    method shouldParseStartTestSuite (line 101) | @Test
    method shouldParseEndTestSuite (line 106) | @Test
    method shouldParseStartTestCase (line 111) | @Test
    method shouldAddErrorToTestCase (line 116) | @Test
    method shouldParsePassedTestCase (line 121) | @Test
    method shouldParseFailedTestCase (line 126) | @Test

FILE: src/test/java/au/com/rayh/OutputParserTests.java
  class OutputParserTests (line 45) | class OutputParserTests {
    method OutputParserTests (line 48) | OutputParserTests(XCodeBuildOutputParser theParser) {
    method shouldIgnoreStartSuiteLineThatContainsFullPath (line 52) | void shouldIgnoreStartSuiteLineThatContainsFullPath() throws Exception {
    method shouldParseStartTestSuite (line 58) | void shouldParseStartTestSuite() throws Exception {
    method shouldParseEndTestSuite (line 66) | void shouldParseEndTestSuite() throws Exception {
    method shouldParseStartTestSuiteXC (line 75) | void shouldParseStartTestSuiteXC() throws Exception {
    method shouldParseEndTestSuiteXC (line 83) | void shouldParseEndTestSuiteXC() throws Exception {
    method shouldParseStartTestCase (line 92) | void shouldParseStartTestCase() throws Exception {
    method shouldAddErrorToTestCase (line 101) | void shouldAddErrorToTestCase() throws Exception {
    method shouldAddUIErrorToTestCase (line 113) | void shouldAddUIErrorToTestCase() throws Exception {
    method shouldParsePassedTestCase (line 125) | void shouldParsePassedTestCase() throws Exception {
    method shouldParseFailedTestCase (line 140) | void shouldParseFailedTestCase() throws Exception {

FILE: src/test/java/au/com/rayh/XCodeBuildHelpParserTest.java
  class XCodeBuildHelpParserTest (line 10) | public class XCodeBuildHelpParserTest {
    method testValidOutput (line 12) | @Test
    method testInvalidOutputNull (line 21) | @Test
    method testInvalidOutputEmpty (line 27) | @Test
    method testInvalidOutputExtraLine (line 34) | @Test

FILE: src/test/java/au/com/rayh/XCodeBuildListParserTest.java
  class XCodeBuildListParserTest (line 10) | public class XCodeBuildListParserTest {
    method testValidOutput (line 13) | @Test
    method testInvalidOutputNull (line 34) | @Test
    method testInvalidOutputEmpty (line 44) | @Test
    method testInvalidOutputExtraLine (line 56) | @Test
    method testInvalidOutputMissngColon (line 68) | @Test

FILE: src/test/java/au/com/rayh/XCodeBuildOutputParserTest.java
  class XCodeBuildOutputParserTest (line 48) | public class XCodeBuildOutputParserTest {
    method setUp (line 51) | @Before
    method tearDown (line 57) | @After
    method shouldIgnoreStartSuiteLineThatContainsFullPath (line 61) | @Test
    method shouldParseStartTestSuite (line 66) | @Test
    method shouldParseEndTestSuite (line 71) | @Test
    method shouldParseStartTestSuiteXC (line 76) | @Test
    method shouldParseEndTestSuiteXC (line 81) | @Test
    method shouldParseStartTestCase (line 86) | @Test
    method shouldAddErrorToTestCase (line 91) | @Test
    method shouldAddUIErrorToTestCase (line 96) | @Test
    method shouldParsePassedTestCase (line 101) | @Test
    method shouldParseFailedTestCase (line 106) | @Test
    method shouldParseFullXCPassingTestOutput1 (line 111) | @Test
    method shouldParseFullXCFailingTestOutput1 (line 117) | @Test
    method shouldParseFullXCFailingTestOutput2 (line 124) | @Test
    method shouldParseFullXCCrashingTestOutput1 (line 130) | @Test
    method parseTestOutput (line 136) | private XCodeBuildOutputParser parseTestOutput(String outputFileName) ...
    method shouldParseFullXCPassingTestComplex1 (line 144) | @Test
    method shouldParseFullXCPassingTestComplex2 (line 151) | @Test

FILE: src/test/java/au/com/rayh/XCodeBuilderTest.java
  class XCodeBuilderTest (line 37) | public class XCodeBuilderTest {
    method setUp (line 39) | @Before
    method tearDown (line 43) | @After
    method shouldSplitXcodeBuildArgumentsWithoutEscapedSpaces (line 47) | @Test
    method shouldSplitXcodeBuildArgumentsWithEscapedSpaces (line 55) | @Test
    method shouldUnquoteWhenSplittingXcodeBuildArgumentsWithIncompleteDoubleQuote (line 64) | @Test
    method shouldUnquoteWhenSplittingXcodeBuildArgumentsWithIncompleteSingleQuote (line 69) | @Test

FILE: src/test/java/au/com/rayh/XcodeProjectParserTest.java
  class XcodeProjectParserTest (line 22) | public class XcodeProjectParserTest {
    method testValidProject (line 24) | @Test
    method testInvalidProject (line 52) | @Test
    method run (line 57) | private static void run(FilePath dir, String... cmds) throws Interrupt...

FILE: src/test/java/au/com/rayh/XcodeTestSummariesParserTest.java
  class XcodeTestSummariesParserTest (line 22) | public class XcodeTestSummariesParserTest {
    method testValidTestSummaries (line 24) | @Test
    method testInvalidTestSummaries (line 37) | @Test
    method run (line 42) | private static void run(FilePath dir, String... cmds) throws Interrupt...
Condensed preview — 250 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (873K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 179,
    "preview": "version: 2\nupdates:\n- package-ecosystem: maven\n  directory: /\n  schedule:\n    interval: weekly\n- package-ecosystem: gith"
  },
  {
    "path": ".github/release-drafter.yml",
    "chars": 18,
    "preview": "_extends: .github\n"
  },
  {
    "path": ".github/workflows/cd.yaml",
    "chars": 1752,
    "preview": "# Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins\n\nname: cd\non:\n "
  },
  {
    "path": ".gitignore",
    "chars": 65,
    "preview": "target\nwork\n.idea\ntest-*\n*.iml\n.DS_Store\n*.orig\n/examples\nTEST-*\n"
  },
  {
    "path": ".mvn/extensions.xml",
    "chars": 415,
    "preview": "<extensions xmlns=\"http://maven.apache.org/EXTENSIONS/1.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:s"
  },
  {
    "path": ".mvn/maven.config",
    "chars": 79,
    "preview": "-Pconsume-incrementals\n-Pmight-produce-incrementals\n-Dchangelist.format=%d.v%s\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 13099,
    "preview": "Changelog\n===\n\n### Newer versions\n\nSee [GitHub releases](https://github.com/jenkinsci/xcode-plugin/releases)\n\n#### Versi"
  },
  {
    "path": "Jenkinsfile",
    "chars": 34,
    "preview": "buildPlugin(platforms: ['linux'])\n"
  },
  {
    "path": "README.md",
    "chars": 43949,
    "preview": "Xcode plugin\n------------\n\nThis plugin adds the ability to call Xcode command line tools to automate build and packaging"
  },
  {
    "path": "pom.xml",
    "chars": 5640,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ P"
  },
  {
    "path": "src/main/java/au/com/rayh/BuildConfiguration.java",
    "chars": 2546,
    "preview": "package au.com.rayh;\n\nimport com.dd.plist.NSDictionary; \nimport com.dd.plist.NSArray;\nimport com.dd.plist.NSNumber;\nimpo"
  },
  {
    "path": "src/main/java/au/com/rayh/DSymFileFilter.java",
    "chars": 1577,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/DeveloperProfile.java",
    "chars": 5010,
    "preview": "package au.com.rayh;\n\nimport com.cloudbees.plugins.credentials.CredentialsProvider;\nimport com.cloudbees.plugins.credent"
  },
  {
    "path": "src/main/java/au/com/rayh/DeveloperProfileLoader.java",
    "chars": 17462,
    "preview": "package au.com.rayh;\n\nimport com.cloudbees.plugins.credentials.CredentialsMatchers;\nimport com.cloudbees.plugins.credent"
  },
  {
    "path": "src/main/java/au/com/rayh/ExportIpa.java",
    "chars": 17033,
    "preview": "package au.com.rayh;\n\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport hudson.*;\nimport hudson.model.*;"
  },
  {
    "path": "src/main/java/au/com/rayh/GlobalConfigurationImpl.java",
    "chars": 7995,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2013 Maur�cio Hanika\n *\n * Permission is hereby granted, free of charge, to an"
  },
  {
    "path": "src/main/java/au/com/rayh/InfoPlist.java",
    "chars": 1679,
    "preview": "package au.com.rayh;\n\nimport hudson.FilePath;\n\n//import org.kohsuke.stapler.DataBoundConstructor;\n\npublic class InfoPlis"
  },
  {
    "path": "src/main/java/au/com/rayh/JenkinsXCodeBuildOutputParser.java",
    "chars": 5319,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/Keychain.java",
    "chars": 1557,
    "preview": "package au.com.rayh;\n\nimport hudson.util.Secret;\nimport org.apache.commons.lang.StringUtils;\nimport org.kohsuke.stapler."
  },
  {
    "path": "src/main/java/au/com/rayh/KeychainPasswordAndPath.java",
    "chars": 2486,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011-2012, CloudBees, Inc., Stephen Connolly.\n *\n * Permission is hereby grant"
  },
  {
    "path": "src/main/java/au/com/rayh/KeychainPasswordAndPathBinding.java",
    "chars": 5040,
    "preview": "/*\n * The MIT License\n *\n *  Copyright (c) 2016, CloudBees, Inc.\n *\n *  Permission is hereby granted, free of charge, to"
  },
  {
    "path": "src/main/java/au/com/rayh/KeychainPasswordAndPathImpl.java",
    "chars": 5169,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011-2016, CloudBees, Inc., Stephen Connolly.\n *\n * Permission is hereby grant"
  },
  {
    "path": "src/main/java/au/com/rayh/KeychainUnlockStep.java",
    "chars": 8338,
    "preview": "package au.com.rayh;\n\nimport com.cloudbees.plugins.credentials.CredentialsMatchers;\nimport com.cloudbees.plugins.credent"
  },
  {
    "path": "src/main/java/au/com/rayh/MobileProvisionParser.java",
    "chars": 1367,
    "preview": "package au.com.rayh;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.apache.commons.lang.StringUtils;\n\n\n/"
  },
  {
    "path": "src/main/java/au/com/rayh/ProjectScheme.java",
    "chars": 902,
    "preview": "package au.com.rayh;\n\npublic class ProjectScheme {\n    //public String parallelizeBuildables;\n    //public String buildI"
  },
  {
    "path": "src/main/java/au/com/rayh/ProjectTarget.java",
    "chars": 579,
    "preview": "package au.com.rayh;\n\nimport java.util.HashMap;\n\npublic class ProjectTarget {\n    public String uuid;\n    //public Strin"
  },
  {
    "path": "src/main/java/au/com/rayh/ProvisioningProfile.java",
    "chars": 1327,
    "preview": "package au.com.rayh;\n\nimport org.kohsuke.stapler.DataBoundConstructor;\nimport hudson.EnvVars;\n\npublic class Provisioning"
  },
  {
    "path": "src/main/java/au/com/rayh/Team.java",
    "chars": 626,
    "preview": "package au.com.rayh;\n\nimport org.kohsuke.stapler.DataBoundConstructor;\n\npublic class Team {\n\n    private String teamName"
  },
  {
    "path": "src/main/java/au/com/rayh/XCArchiveFileFilter.java",
    "chars": 1584,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/XCodeAction.java",
    "chars": 479,
    "preview": "package au.com.rayh;\n\nimport hudson.model.InvisibleAction;\nimport org.kohsuke.stapler.DataBoundConstructor;\n\n/**\n * Simp"
  },
  {
    "path": "src/main/java/au/com/rayh/XCodeBuildNumberTokenMacro.java",
    "chars": 882,
    "preview": "package au.com.rayh;\r\n\r\nimport hudson.Extension;\r\nimport hudson.model.AbstractBuild;\r\nimport hudson.model.TaskListener;\r"
  },
  {
    "path": "src/main/java/au/com/rayh/XCodeBuildOutputParser.java",
    "chars": 13407,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/XCodeBuilder.java",
    "chars": 94873,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeBuildHelpParser.java",
    "chars": 771,
    "preview": "package au.com.rayh;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.apache.commons.lang.StringUtils;\n\n/*"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeBuildListParser.java",
    "chars": 1365,
    "preview": "package au.com.rayh;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.apache.commons.lang.StringUtils;\n\n\n/"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeCredentialsHelper.java",
    "chars": 1590,
    "preview": "package au.com.rayh;\n\nimport com.cloudbees.plugins.credentials.CredentialsMatchers;\nimport com.cloudbees.plugins.credent"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeDeclarativeCredentialsHandler.java",
    "chars": 2246,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2018, CloudBees, Inc.\n *\n * Permission is hereby granted, free of charge, to a"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeProject.java",
    "chars": 399,
    "preview": "package au.com.rayh;\n\n//import org.kohsuke.stapler.DataBoundConstructor;\nimport java.util.HashMap;\n\npublic class XcodePr"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeProjectFileFilter.java",
    "chars": 1596,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeProjectParser.java",
    "chars": 14645,
    "preview": "package au.com.rayh;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.DirectoryStream;\nimport java"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeSchemeFileFilter.java",
    "chars": 1589,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/XcodeTestSummariesParser.java",
    "chars": 7215,
    "preview": "package au.com.rayh;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.net.InetAddress;\nimport java."
  },
  {
    "path": "src/main/java/au/com/rayh/report/TestCase.java",
    "chars": 2435,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/report/TestError.java",
    "chars": 1792,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2014 David Baker\n *\n * Permission is hereby granted, free of charge, to any pe"
  },
  {
    "path": "src/main/java/au/com/rayh/report/TestFailure.java",
    "chars": 2032,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/au/com/rayh/report/TestSuite.java",
    "chars": 3603,
    "preview": "/*\n * The MIT License\n *\n * Copyright (c) 2011 Ray Yamamoto Hilton\n *\n * Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/java/hudson/plugins/xcode/XcodeInstallation.java",
    "chars": 4598,
    "preview": "package hudson.plugins.xcode;\n\nimport hudson.EnvVars;\nimport hudson.Extension;\nimport hudson.init.Initializer;\nimport hu"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/config.groovy",
    "chars": 1639,
    "preview": "package au.com.rayh.DeveloperProfile\n\nimport java.security.GeneralSecurityException\nimport java.security.cert.Certificat"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/config_ja.properties",
    "chars": 261,
    "preview": "*.developerprofile\\ \\ File=*.developerprofile \\u30d5\\u30a1\\u30a4\\u30eb\nPassword=\\u30d1\\u30b9\\u30ef\\u30fc\\u30c9\nContents="
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/help-description.html",
    "chars": 185,
    "preview": "<div>\n    Any one-liner text to help you remember what this certificate is\n    among other certificates. Jenkins will us"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/help-description_ja.html",
    "chars": 83,
    "preview": "<div>\n    この証明書が何であるかを覚えておくための任意の一行のテキスト。\n    Jenkinsはこのテキストを使用して証明書を選択します。\n</div>\n"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/help-password.html",
    "chars": 79,
    "preview": "<div>\n    The password you set when you exported your developer profile.\n</div>"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/help-password_ja.html",
    "chars": 49,
    "preview": "<div>\n    開発者プロファイルをエクスポートしたときに設定したパスワード。\n</div>\n"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/help.html",
    "chars": 412,
    "preview": "<div>\n    Register your developer profile to Jenkins so that you can sign binaries built on Jenkins with your identities"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/help_ja.html",
    "chars": 337,
    "preview": "<div>\n    開発者プロファイルをJenkinsに登録しておくと、Jenkinsでビルドされたバイナリに自分のIDで署名することができます。\n    詳しくは <a href=\"https://developer.apple.com/"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfile/upload.groovy",
    "chars": 261,
    "preview": "package au.com.rayh.DeveloperProfile\n\n\"\"\"\n<form method=\"post\"\n      action=\"submit?id=${request.getParameter('id')}\"\n   "
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfileLoader/config.jelly",
    "chars": 5415,
    "preview": "<?jelly escape-by-default='true'?>\n<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permi"
  },
  {
    "path": "src/main/resources/au/com/rayh/DeveloperProfileLoader/config_ja.properties",
    "chars": 4186,
    "preview": "Developer\\ Profile=\\u958B\\u767A\\u8005\\u30D7\\u30ED\\u30D5\\u30A1\\u30A4\\u30EB\nImport\\ into\\ existing\\ Keychain=\\u65E2\\u5B58\\"
  },
  {
    "path": "src/main/resources/au/com/rayh/ExportIpa/config.jelly",
    "chars": 17151,
    "preview": "<?jelly escape-by-default='true'?>\n<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permi"
  },
  {
    "path": "src/main/resources/au/com/rayh/ExportIpa/config_ja.properties",
    "chars": 12351,
    "preview": "Archive\\ directory=\\u30a2\\u30fc\\u30ab\\u30a4\\u30d6\\u306e\\u30c7\\u30a3\\u30ec\\u30af\\u30c8\\u30ea\nSpecify\\ the\\ location\\ of\\ "
  },
  {
    "path": "src/main/resources/au/com/rayh/ExportIpa/help-archiveDir.html",
    "chars": 1704,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/ExportIpa/help-archiveDir_ja.html",
    "chars": 1587,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/GlobalConfigurationImpl/config.jelly",
    "chars": 5417,
    "preview": "<?jelly escape-by-default='true'?>\n<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permi"
  },
  {
    "path": "src/main/resources/au/com/rayh/GlobalConfigurationImpl/config_ja.properties",
    "chars": 3791,
    "preview": "Xcode\\ Builder=Xcode\\u30D3\\u30EB\\u30C9\nxcodebuild\\ executable\\ path=xcodebuild\\u5B9F\\u884C\\u30D5\\u30A1\\u30A4\\u30EB\\u306E"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/config-variables.jelly",
    "chars": 1604,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\nThe MIT License\n\nCopyright 2013 jglick.\n\nPermission is hereby granted, free "
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/config-variables_ja.properties",
    "chars": 794,
    "preview": "Keychain\\ Path\\ Variable=\\u30AD\\u30FC\\u30C1\\u30A7\\u30FC\\u30F3\\u306E\\u30D1\\u30B9\\u3092\\u4FDD\\u5B58\\u3059\\u308B\\u5909\\u657"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/help-inSearchPathVariable.html",
    "chars": 308,
    "preview": "<div>\n    Name of a variable that stores information on whether to set the keychain stored in the 'Credentials' to the s"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/help-inSearchPathVariable_ja.html",
    "chars": 139,
    "preview": "<div>\n    認証情報に保存されているキーチェーンをサーチパスに設定するかどうかの情報を格納する変数の名前。<br />\n    ここで指定された名前の環境変数に値が格納されるのでシェルスクリプトなどで認証情報に保存されている情報を利"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/help-keychainPathVariable.html",
    "chars": 284,
    "preview": "<div>\n    Name of a variable that contains information about the keychain path stored in the 'Credentials'.<br />\n    Be"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/help-keychainPathVariable_ja.html",
    "chars": 126,
    "preview": "<div>\n    認証情報に保存されているキーチェーンのパス情報を格納する変数の名前。<br />\n    ここで指定された名前の環境変数に値が格納されるのでシェルスクリプトなどで認証情報に保存されている情報を利用することができます。\n<"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/help-passwordVariable.html",
    "chars": 288,
    "preview": "<div>\n    Name of a variable that contains information about the keychain password stored in the 'Credentials'.<br />\n  "
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathBinding/help-passwordVariable_ja.html",
    "chars": 130,
    "preview": "<div>\n    認証情報に保存されているキーチェーンのパスワード情報を格納する変数の名前\n。<br />\n    ここで指定された名前の環境変数に値が格納されるのでシェルスクリプトなどで認証情報に保存されている情報を利用することができま"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/credentials.jelly",
    "chars": 2185,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?jelly escape-by-default='true'?>\n<!--\n ~ The MIT License\n ~\n ~ Copyright (c) 20"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/credentials_ja.properties",
    "chars": 1943,
    "preview": "Saved\\ keychain\\ configurations=\\u4FDD\\u5B58\\u3055\\u308C\\u305F\\u30AD\\u30FC\\u30C1\\u30A7\\u30FC\\u30F3\\u306E\\u8A2D\\u5B9A\nAn\\"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-description.html",
    "chars": 185,
    "preview": "<div>\n    Any one-liner text to help you remember what this certificate is\n    among other certificates. Jenkins will us"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-description_ja.html",
    "chars": 83,
    "preview": "<div>\n    この証明書が何であるかを覚えておくための任意の一行のテキスト。\n    Jenkinsはこのテキストを使用して証明書を選択します。\n</div>\n"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-id.html",
    "chars": 316,
    "preview": "<div>\n    An internal unique ID by which these credentials are identified from jobs and other configuration.\n    Normall"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-id_ja.html",
    "chars": 187,
    "preview": "<div>\n    この資格情報をジョブやその他の設定で識別するための内部固有IDです。<br />\n    この項目を空白のままにした場合にはIDが自動生成されます。これはGUIインターフェイスを使用して作成されたジョブに適しています。<"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-keychainPath.html",
    "chars": 146,
    "preview": "<div>\n    The path of the keychain to use to retrieve certificates to sign the package (example : ${HOME}/Library/Keycha"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-keychainPath_ja.html",
    "chars": 95,
    "preview": "<div>\n    パッケージに署名するための証明書を取得するキーチェーンのパス。 (例: ${HOME}/Library/Keychains/login.keychain)\n</div>\n"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-password.html",
    "chars": 98,
    "preview": "<div>\n    The password of the keychain to use to retrieve certificates to sign the package.\n</div>"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainPasswordAndPathImpl/help-password_ja.html",
    "chars": 52,
    "preview": "<div>\n    パッケージに署名するための証明書を取得するキーチェーンのパスワード。\n</div>\n"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainUnlockStep/config.jelly",
    "chars": 4085,
    "preview": "<?jelly escape-by-default='true'?>\n<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permi"
  },
  {
    "path": "src/main/resources/au/com/rayh/KeychainUnlockStep/config_ja.properties",
    "chars": 4126,
    "preview": "Developer\\ Profile=\\u958B\\u767A\\u8005\\u30D7\\u30ED\\u30D5\\u30A1\\u30A4\\u30EB\nImport\\ into\\ existing\\ Keychain=\\u65E2\\u5B58\\"
  },
  {
    "path": "src/main/resources/au/com/rayh/Messages.properties",
    "chars": 10919,
    "preview": "#\n# The MIT License\n#\n# Copyright (c) 2011 Ray Yamamoto Hilton\n#\n# Permission is hereby granted, free of charge, to any "
  },
  {
    "path": "src/main/resources/au/com/rayh/Messages_ja.properties",
    "chars": 20923,
    "preview": "#\n# The MIT License\n#\n# Copyright (c) 2011 Ray Yamamoto Hilton\n#\n# Permission is hereby granted, free of charge, to any "
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/config.jelly",
    "chars": 23540,
    "preview": "<?jelly escape-by-default='true'?>\n<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permi"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/config_ja.properties",
    "chars": 20587,
    "preview": "General\\ build\\ settings=\\u4E00\\u822C\\u7684\\u306A\\u30D3\\u30EB\\u30C9\\u8A2D\\u5B9A\nXcode\\ Tools\\ Version=Xcode tools\\u306E\\"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-allowFailingBuildResults.html",
    "chars": 1572,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2013 Tim Ekl\n  ~\n  ~ Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-allowFailingBuildResults_ja.html",
    "chars": 1418,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2013 Tim Ekl\n  ~\n  ~ Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-buildDir.html",
    "chars": 1811,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-buildDir_ja.html",
    "chars": 1607,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-buildIpa.html",
    "chars": 1473,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-buildIpa_ja.html",
    "chars": 1442,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-bundleID.html",
    "chars": 1274,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-bundleIDInfoPlistPath.html",
    "chars": 1406,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-bundleIDInfoPlistPath_ja.html",
    "chars": 1356,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-bundleID_ja.html",
    "chars": 1254,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cfBundleShortVersionStringValue.html",
    "chars": 1540,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cfBundleShortVersionStringValue_ja.html",
    "chars": 1488,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cfBundleVersionValue.html",
    "chars": 1816,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cfBundleVersionValue_ja.html",
    "chars": 1654,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-changeBundleID.html",
    "chars": 1499,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-changeBundleID_ja.html",
    "chars": 1360,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cleanBeforeBuild.html",
    "chars": 1382,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cleanBeforeBuild_ja.html",
    "chars": 1290,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cleanResultBundlePath.html",
    "chars": 1419,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-cleanResultBundlePath_ja.html",
    "chars": 1339,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-codeSigningIdentity.html",
    "chars": 1480,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-codeSigningIdentity_ja.html",
    "chars": 1349,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-configuration.html",
    "chars": 1337,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-configuration_ja.html",
    "chars": 1288,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-embeddedProfileFile.html",
    "chars": 1292,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-embeddedProfileFile_ja.html",
    "chars": 1275,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-generateArchive.html",
    "chars": 1435,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2013 Jeffrey Todd Ligon\n  ~\n  ~ Permission is hereby granted, free of cha"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-generateArchive_ja.html",
    "chars": 1359,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2013 Jeffrey Todd Ligon\n  ~\n  ~ Permission is hereby granted, free of cha"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-globalDevelopmentTeam_ja.html",
    "chars": 1354,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-globalKeychainName_ja.html",
    "chars": 1235,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-interpretTargetAsRegEx.html",
    "chars": 1318,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-interpretTargetAsRegEx_ja.html",
    "chars": 1283,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-ipaName_ja.html",
    "chars": 1777,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-keychainName.html",
    "chars": 1292,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-keychainName_ja.html",
    "chars": 1242,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-keychainPath.html",
    "chars": 1325,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-keychainPath_ja.html",
    "chars": 1277,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-keychainPwd.html",
    "chars": 1276,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-keychainPwd_ja.html",
    "chars": 1229,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-logfileOutputDirectory.html",
    "chars": 1522,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-logfileOutputDirectory_ja.html",
    "chars": 1422,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-resultBundlePath.html",
    "chars": 1633,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-resultBundlePath_ja.html",
    "chars": 1497,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-sdk.html",
    "chars": 1552,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-sdk_ja.html",
    "chars": 1436,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-signIpaOnXcrun.html",
    "chars": 1762,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-signIpaOnXcrun_ja.html",
    "chars": 1762,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-symRoot.html",
    "chars": 1783,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-symRoot_ja.html",
    "chars": 1629,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-target.html",
    "chars": 1527,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-target_ja.html",
    "chars": 1397,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-unlockKeychain_ja.html",
    "chars": 1235,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-useLegacyBuildSystem.html",
    "chars": 1607,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-useLegacyBuildSystem_ja.html",
    "chars": 1420,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-xcodeProjectFile_ja.html",
    "chars": 1359,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-xcodeProjectPath_ja.html",
    "chars": 1329,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-xcodeSchema_ja.html",
    "chars": 1321,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-xcodeWorkspaceFile_ja.html",
    "chars": 1306,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-xcodebuildArguments.html",
    "chars": 1295,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/resources/au/com/rayh/XCodeBuilder/help-xcodebuildArguments_ja.html",
    "chars": 1237,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/resources/hudson/plugins/xcode/XcodeInstallation/config.jelly",
    "chars": 366,
    "preview": "<?jelly escape-by-default='true'?>\n<j:jelly xmlns:j=\"jelly:core\" xmlns:st=\"jelly:stapler\" xmlns:d=\"jelly:define\" xmlns:l"
  },
  {
    "path": "src/main/resources/hudson/plugins/xcode/XcodeInstallation/config_it.properties",
    "chars": 77,
    "preview": "Name=Nome\nPath\\ to\\ Xcode\\ tools=Percorso del file eseguibile Xcode utensili\n"
  },
  {
    "path": "src/main/resources/hudson/plugins/xcode/XcodeInstallation/config_ja.properties",
    "chars": 1191,
    "preview": "# The MIT License\n#\n# Copyright (c) 2016-, Seiji Sogabe\n#\n# Permission is hereby granted, free of charge, to any person "
  },
  {
    "path": "src/main/resources/hudson/plugins/xcode/XcodeInstallation/help-home.html",
    "chars": 103,
    "preview": "<div>\n    Set path to Xcode tools. This is the path displayed when executing \"xcode-select -p\".\n</div>\n"
  },
  {
    "path": "src/main/resources/hudson/plugins/xcode/XcodeInstallation/help-home_ja.html",
    "chars": 77,
    "preview": "<div>\n    Xcode toolsへのパスを指定します。これは\"xcode-select -p\"を実行した時に表示されるパスです。\n</div>\n"
  },
  {
    "path": "src/main/resources/index.jelly",
    "chars": 1457,
    "preview": "<?jelly escape-by-default='true'?>\n<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permi"
  },
  {
    "path": "src/main/webapp/help/help-appIDandProvisionUUID.html",
    "chars": 1542,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-appIDandProvisionUUID_ja.html",
    "chars": 1401,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-assetPackManifestURL.html",
    "chars": 1503,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-assetPackManifestURL_ja.html",
    "chars": 1385,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-automaticSigning.html",
    "chars": 1531,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-automaticSigning_ja.html",
    "chars": 1363,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2014 Esteban Bouza Padin\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-bundleID.html",
    "chars": 1462,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-bundleID_ja.html",
    "chars": 1358,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-compileBitcode.html",
    "chars": 1329,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-compileBitcode_ja.html",
    "chars": 1285,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-copyProvisioningProfile.html",
    "chars": 1764,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-copyProvisioningProfile_ja.html",
    "chars": 1554,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-credentialKeychainId.html",
    "chars": 1342,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-credentialKeychainId_ja.html",
    "chars": 1260,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-developmentTeamID.html",
    "chars": 1439,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-developmentTeamID_ja.html",
    "chars": 1348,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-displayImageURL.html",
    "chars": 1378,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-displayImageURL_ja.html",
    "chars": 1312,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-embedOnDemandResources.html",
    "chars": 1534,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-embedOnDemandResources_ja.html",
    "chars": 1419,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-fullSizeImageURL.html",
    "chars": 1380,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-fullSizeImageURL_ja.html",
    "chars": 1313,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-globalDevelopmentTeam.html",
    "chars": 1495,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-globalDevelopmentTeam_ja.html",
    "chars": 1354,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2017 Bryan Lahartinger\n  ~\n  ~ Permission is hereby granted, free of char"
  },
  {
    "path": "src/main/webapp/help/help-globalKeychainName.html",
    "chars": 1283,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-globalKeychainName_ja.html",
    "chars": 1235,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importDeveloperProfile.html",
    "chars": 1544,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importDeveloperProfileId.html",
    "chars": 1384,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importDeveloperProfileId_ja.html",
    "chars": 1314,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importDeveloperProfile_ja.html",
    "chars": 1388,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importIntoExistingKeychain.html",
    "chars": 1867,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importIntoExistingKeychain_ja.html",
    "chars": 1542,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importKeychainId.html",
    "chars": 1312,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importKeychainId_ja.html",
    "chars": 1252,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importKeychainName.html",
    "chars": 1304,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-importKeychainName_ja.html",
    "chars": 1244,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaExportMethod.html",
    "chars": 1330,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaExportMethod_ja.html",
    "chars": 1280,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaManifestPlistUrl.html",
    "chars": 1410,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaManifestPlistUrl_ja.html",
    "chars": 1325,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaName.html",
    "chars": 2015,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaName_ja.html",
    "chars": 1777,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaOutputDirectory.html",
    "chars": 1275,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-ipaOutputDirectory_ja.html",
    "chars": 1254,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 Ray Yamamoto Hilton\n  ~\n  ~ Permission is hereby granted, free of ch"
  },
  {
    "path": "src/main/webapp/help/help-manifestPlistURL.html",
    "chars": 1353,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  },
  {
    "path": "src/main/webapp/help/help-manifestPlistURL_ja.html",
    "chars": 1284,
    "preview": "<!--\n  ~ The MIT License\n  ~\n  ~ Copyright (c) 2011 eXo platform\n  ~\n  ~ Permission is hereby granted, free of charge, t"
  }
]

// ... and 50 more files (download for full content)

About this extraction

This page contains the full source code of the jenkinsci/xcode-plugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 250 files (784.6 KB), approximately 221.2k tokens, and a symbol index with 591 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!