Skip to content

Commit

Permalink
Support custom xcconfig file path (#297)
Browse files Browse the repository at this point in the history
Allow passing a file path to an existing xcconfig file, instead of providing the file contents directly.

* `xcconfig_content` can now be a path to a xcconfig file, or left empty. This allows using a custom xcconfig file that already exists in the repository.
  • Loading branch information
lpusok authored May 25, 2022
1 parent 16729ba commit d610089
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 62 deletions.
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ To configure the Step:

Under **xcodebuild configuration**:
1. **Build configuration**: Specify Xcode Build Configuration. The Step uses the provided Build Configuration's Build Settings to understand your project's code signing configuration. If not provided, the Archive action's default Build Configuration will be used.
2. **Build settings (xconfig)**: Build settings to override the project's build settings. The build settings must be separated by a newline character (`\n`).
2. **Build settings (xcconfig)**: Build settings to override the project's build settings. Can be the contents, file path or empty.
3. **Perform clean action**: If this input is set, a `clean` xcodebuild action will be performed besides the `archive` action.

Under **Xcode build log formatting**:
Expand Down Expand Up @@ -67,6 +67,38 @@ Add this step directly to your workflow in the [Bitrise Workflow Editor](https:/

You can also run this step directly with [Bitrise CLI](https://github.com/bitrise-io/bitrise).

### Examples

Build a development IPA:
```yaml
- xcode-archive:
inputs:
- project_path: ./ios-sample/ios-sample.xcodeproj
- scheme: ios-sample
- distribution_method: development
```
Build a development IPA with custom xcconfig content:
```yaml
- xcode-archive:
inputs:
- project_path: ./ios-sample/ios-sample.xcodeproj
- scheme: ios-sample
- distribution_method: development
- xcconfig_content: |
CODE_SIGN_IDENTITY = Apple Development
```
Build a development IPA with custom xcconfig file path:
```yaml
- xcode-archive:
inputs:
- project_path: ./ios-sample/ios-sample.xcodeproj
- scheme: ios-sample
- distribution_method: development
- xcconfig_content: ./ios-sample/ios-sample/Configurations/Dev.xcconfig
```
## ⚙️ Configuration
<details>
Expand All @@ -78,7 +110,7 @@ You can also run this step directly with [Bitrise CLI](https://github.com/bitris
| `scheme` | Xcode Scheme name. The input value sets xcodebuild's `-scheme` option. | required | `$BITRISE_SCHEME` |
| `distribution_method` | Describes how Xcode should export the archive. | required | `development` |
| `configuration` | Xcode Build Configuration. If not specified, the default Build Configuration will be used. The input value sets xcodebuild's `-configuration` option. | | |
| `xcconfig_content` | Build settings to override the project's build settings. Build settings must be separated by newline character (`\n`). Example: ``` COMPILER_INDEX_STORE_ENABLE = NO ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES ``` The input value sets xcodebuild's `-xcconfig` option. | | `COMPILER_INDEX_STORE_ENABLE = NO` |
| `xcconfig_content` | Build settings to override the project's build settings, using xcodebuild's `-xcconfig` option. If empty, no setting is changed. This is required when the `-xcconfig` additional option is used. When set it can be either: 1. Existing `.xcconfig` file path. Example: `./ios-sample/ios-sample/Configurations/Dev.xcconfig` 2. The contents of a newly created temporary `.xcconfig` file. (This is the default.) Build settings must be separated by newline character (`\n`). Example: ``` COMPILER_INDEX_STORE_ENABLE = NO ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES ``` | | `COMPILER_INDEX_STORE_ENABLE = NO` |
| `perform_clean_action` | If this input is set, `clean` xcodebuild action will be performed besides the `archive` action. | required | `no` |
| `xcodebuild_options` | Additional options to be added to the executed xcodebuild command. | | |
| `log_formatter` | Defines how `xcodebuild` command's log is formatted. Available options: - `xcpretty`: The xcodebuild command's output will be prettified by xcpretty. - `xcodebuild`: Only the last 20 lines of raw xcodebuild output will be visible in the build log. The raw xcodebuild log will be exported in both cases. | required | `xcpretty` |
Expand All @@ -89,6 +121,7 @@ You can also run this step directly with [Bitrise CLI](https://github.com/bitris
| `passphrase_list` | Passphrases for the provided code signing certificates. Specify as many passphrases as many Code signing certificate URL provided, separated by a pipe (`\|`) character. Certificates without a passphrase: for using a single certificate, leave this step input empty. For multiple certificates, use the separator as if there was a passphrase (examples: `pass\|`, `\|pass\|`, `\|`) | sensitive | `$BITRISE_CERTIFICATE_PASSPHRASE` |
| `keychain_path` | Path to the Keychain where the code signing certificates will be installed. | required | `$HOME/Library/Keychains/login.keychain` |
| `keychain_password` | Password for the provided Keychain. | required, sensitive | `$BITRISE_KEYCHAIN_PASSWORD` |
| `fallback_provisioning_profile_url_list` | If set, provided provisioning profiles will be used on Automatic code signing error. URL of the provisioning profile to download. Multiple URLs can be specified, separated by a newline or pipe (`\|`) character. You can specify a local path as well, using the `file://` scheme. For example: `file://./BuildAnything.mobileprovision`. Can also provide a local directory that contains files with `.mobileprovision` extension. For example: `./profilesDirectory/` | sensitive | |
| `export_development_team` | The Developer Portal team to use for this export Defaults to the team used to build the archive. Defining this is also required when Automatic Code Signing is set to `apple-id` and the connected account belongs to multiple teams. | | |
| `compile_bitcode` | For __non-App Store__ exports, should Xcode re-compile the app from bitcode? | required | `yes` |
| `upload_bitcode` | For __App Store__ exports, should the package include bitcode? | required | `yes` |
Expand Down
21 changes: 21 additions & 0 deletions additional_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import "github.com/bitrise-io/go-utils/sliceutil"

func generateAdditionalOptions(platform string, customOptions []string) []string {
destination := "generic/platform=" + platform
destinationOptions := []string{"-destination", destination}

var options []string
if len(customOptions) != 0 {
if !sliceutil.IsStringInSlice("-destination", customOptions) {
options = append(options, destinationOptions...)
}

options = append(options, customOptions...)
} else {
options = append(options, destinationOptions...)
}

return options
}
41 changes: 41 additions & 0 deletions additional_options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"testing"

"github.com/stretchr/testify/require"
)

func Test_generateAdditionalOptions(t *testing.T) {
tests := []struct {
name string
platform string
customOptions []string
want []string
}{
{
name: "no custom options",
platform: "iOS",
want: []string{"-destination", "generic/platform=iOS"},
},
{
name: "custom opts",
platform: "iOS",
customOptions: []string{"-scmProvider", "system"},
want: []string{"-destination", "generic/platform=iOS", "-scmProvider", "system"},
},
{
name: "custom opts with destination",
platform: "iOS",
customOptions: []string{"-scmProvider", "system", "-destination", "generic/platform=iOS"},
want: []string{"-scmProvider", "system", "-destination", "generic/platform=iOS"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := generateAdditionalOptions(tt.platform, tt.customOptions)

require.Equal(t, tt.want, got)
})
}
}
1 change: 1 addition & 0 deletions bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ workflows:
- git::https://github.com/bitrise-steplib/steps-readme-generator.git@main:
inputs:
- contrib_section: docs/contribution.md
- example_section: docs/examples.md
31 changes: 31 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
### Examples

Build a development IPA:
```yaml
- xcode-archive:
inputs:
- project_path: ./ios-sample/ios-sample.xcodeproj
- scheme: ios-sample
- distribution_method: development
```
Build a development IPA with custom xcconfig content:
```yaml
- xcode-archive:
inputs:
- project_path: ./ios-sample/ios-sample.xcodeproj
- scheme: ios-sample
- distribution_method: development
- xcconfig_content: |
CODE_SIGN_IDENTITY = Apple Development
```
Build a development IPA with custom xcconfig file path:
```yaml
- xcode-archive:
inputs:
- project_path: ./ios-sample/ios-sample.xcodeproj
- scheme: ios-sample
- distribution_method: development
- xcconfig_content: ./ios-sample/ios-sample/Configurations/Dev.xcconfig
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/bitrise-io/go-utils v1.0.1
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.2
github.com/bitrise-io/go-xcode v1.0.6
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.14
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.15
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.2 h1:w3fwgLLmxMOpYNa6W5aLtJZE8M8+
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.2/go.mod h1:sy+Ir1X8P3tAAx/qU/r+hqDjHDcrMjIzDEvId1wqNc4=
github.com/bitrise-io/go-xcode v1.0.6 h1:hSKwkDXUn9/gMk6HiJRUvurGWelfQEBWcO7JAvXi+y8=
github.com/bitrise-io/go-xcode v1.0.6/go.mod h1:Y0Wu2dXm0MilJ/4D3+gPHaNMlUcP+1DjIPoLPykq7wY=
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.14 h1:Tfo5QuCZmb/BTC8QWEhPxuP02FzjnjEE19jTzQFag2o=
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.14/go.mod h1:IhG2l/bM8+809Jlwt4hgRzOkRfPmhEybfWMOJdEGnEU=
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.15 h1:swynA2yBvKWdMEPDz/GFM55ELekauWIvtDCLWKScVhU=
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.15/go.mod h1:IhG2l/bM8+809Jlwt4hgRzOkRfPmhEybfWMOJdEGnEU=
github.com/bitrise-io/pkcs12 v0.0.0-20211108084543-e52728e011c8 h1:kmvU8AxrNTxXsVPKepBHD8W+eCVmeaKyTkRuUJB2K38=
github.com/bitrise-io/pkcs12 v0.0.0-20211108084543-e52728e011c8/go.mod h1:UiXKNs0essbC14a2TvGlnUKo9isP9m4guPrp8KJHJpU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
77 changes: 39 additions & 38 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ type Inputs struct {
// Config ...
type Config struct {
Inputs
XcodeMajorVersion int
CodesignManager *codesign.Manager // nil if automatic code signing is "off"
XcodeMajorVersion int
XcodebuildAdditionalOptions []string
CodesignManager *codesign.Manager // nil if automatic code signing is "off"
}

var envRepository = env.NewRepository()
Expand Down Expand Up @@ -199,6 +200,7 @@ type XcodeArchiveStep struct {
xcodeVersionProvider xcodeVersionProvider
stepInputParser stepconf.InputParser
pathProvider pathutil.PathProvider
pathChecker pathutil.PathChecker
fileManager fileutil.FileManager
}

Expand All @@ -208,6 +210,7 @@ func NewXcodeArchiveStep() XcodeArchiveStep {
xcodeVersionProvider: newXcodebuildXcodeVersionProvider(),
stepInputParser: stepconf.NewInputParser(env.NewRepository()),
pathProvider: pathutil.NewPathProvider(),
pathChecker: pathutil.NewPathChecker(),
fileManager: fileutil.NewFileManager(),
}
}
Expand All @@ -226,6 +229,20 @@ func (s XcodeArchiveStep) ProcessInputs() (Config, error) {
logger.EnableDebugLog(config.VerboseLog)
v1log.SetEnableDebugLog(config.VerboseLog) // For compatibility

var err error
config.XcodebuildAdditionalOptions, err = shellquote.Split(inputs.XcodebuildOptions)
if err != nil {
return Config{}, fmt.Errorf("provided XcodebuildOptions (%s) are not valid CLI parameters: %s", inputs.XcodebuildOptions, err)
}

if strings.TrimSpace(config.XcconfigContent) == "" {
config.XcconfigContent = ""
}
if sliceutil.IsStringInSlice("-xcconfig", config.XcodebuildAdditionalOptions) &&
config.XcconfigContent != "" {
return Config{}, fmt.Errorf("`-xcconfig` option found in XcodebuildOptions (`xcodebuild_options`), please clear Build settings (xcconfig) (`xcconfig_content`) input as only one can be set")
}

if config.ExportOptionsPlistContent != "" {
var options map[string]interface{}
if _, err := plist.Unmarshal([]byte(config.ExportOptionsPlistContent), &options); err != nil {
Expand Down Expand Up @@ -438,7 +455,7 @@ type xcodeArchiveOpts struct {

PerformCleanAction bool
XcconfigContent string
CustomOptions []string
AdditionalOptions []string

CacheLevel string
}
Expand Down Expand Up @@ -496,12 +513,14 @@ func (s XcodeArchiveStep) xcodeArchive(opts xcodeArchiveOpts) (xcodeArchiveOutpu
archiveCmd.SetCustomBuildAction("clean")
}

xcconfigWriter := xcconfig.NewWriter(s.pathProvider, s.fileManager)
xcconfigPath, err := xcconfigWriter.Write(opts.XcconfigContent)
if err != nil {
return out, fmt.Errorf("failed to write xcconfig file contents: %w", err)
if opts.XcconfigContent != "" {
xcconfigWriter := xcconfig.NewWriter(s.pathProvider, s.fileManager, s.pathChecker)
xcconfigPath, err := xcconfigWriter.Write(opts.XcconfigContent)
if err != nil {
return out, fmt.Errorf("failed to write xcconfig file contents: %w", err)
}
archiveCmd.SetXCConfigPath(xcconfigPath)
}
archiveCmd.SetXCConfigPath(xcconfigPath)

tmpDir, err := v1pathutil.NormalizedOSTempDirPath("xcodeArchive")
if err != nil {
Expand All @@ -514,21 +533,8 @@ func (s XcodeArchiveStep) xcodeArchive(opts xcodeArchiveOpts) (xcodeArchiveOutpu
archiveCmd.SetAuthentication(*opts.XcodeAuthOptions)
}

destination := "generic/platform=" + string(platform)
destinationOptions := []string{"-destination", destination}

options := []string{}
if len(opts.CustomOptions) != 0 {
if !sliceutil.IsStringInSlice("-destination", opts.CustomOptions) {
options = append(options, destinationOptions...)
}

options = append(options, opts.CustomOptions...)
} else {
options = append(options, destinationOptions...)
}

archiveCmd.SetCustomOptions(options)
additionalOptions := generateAdditionalOptions(string(platform), opts.AdditionalOptions)
archiveCmd.SetCustomOptions(additionalOptions)

var swiftPackagesPath string
if opts.XcodeMajorVersion >= 11 {
Expand Down Expand Up @@ -776,10 +782,10 @@ type RunOpts struct {
CodesignManager *codesign.Manager

// Archive
PerformCleanAction bool
XcconfigContent string
XcodebuildOptions string
CacheLevel string
PerformCleanAction bool
XcconfigContent string
XcodebuildAdditionalOptions []string
CacheLevel string

// IPA Export
CustomExportOptionsPlistContent string
Expand Down Expand Up @@ -810,17 +816,12 @@ func (s XcodeArchiveStep) Run(opts RunOpts) (RunOut, error) {
authOptions *xcodebuild.AuthenticationParams
)

customOptions, err := shellquote.Split(opts.XcodebuildOptions)
if err != nil {
return out, fmt.Errorf("provided XcodebuildOptions (%s) are not valid CLI parameters: %s", opts.XcodebuildOptions, err)
}

logger.Println()
if opts.XcodeMajorVersion >= 11 {
// Resolve Swift package dependencies, so running -showBuildSettings later is faster later
// Specifying a scheme is required for workspaces
resolveDepsCmd := xcodebuild.NewResolvePackagesCommandModel(opts.ProjectPath, opts.Scheme, opts.Configuration)
resolveDepsCmd.SetCustomOptions(customOptions)
resolveDepsCmd.SetCustomOptions(opts.XcodebuildAdditionalOptions)
if err := resolveDepsCmd.Run(); err != nil {
logger.Warnf("%s", err)
}
Expand Down Expand Up @@ -886,7 +887,7 @@ func (s XcodeArchiveStep) Run(opts RunOpts) (RunOut, error) {

PerformCleanAction: opts.PerformCleanAction,
XcconfigContent: opts.XcconfigContent,
CustomOptions: customOptions,
AdditionalOptions: opts.XcodebuildAdditionalOptions,
CacheLevel: opts.CacheLevel,
}
archiveOut, err := s.xcodeArchive(archiveOpts)
Expand Down Expand Up @@ -1171,10 +1172,10 @@ func RunStep() error {

CodesignManager: config.CodesignManager,

PerformCleanAction: config.PerformCleanAction,
XcconfigContent: config.XcconfigContent,
XcodebuildOptions: config.XcodebuildOptions,
CacheLevel: config.CacheLevel,
PerformCleanAction: config.PerformCleanAction,
XcconfigContent: config.XcconfigContent,
XcodebuildAdditionalOptions: config.XcodebuildAdditionalOptions,
CacheLevel: config.CacheLevel,

CustomExportOptionsPlistContent: config.ExportOptionsPlistContent,
ExportMethod: config.ExportMethod,
Expand Down
Loading

0 comments on commit d610089

Please sign in to comment.