diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 568990c..9a2e326 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,35 +1,37 @@
version: 2
updates:
- - package-ecosystem: "github-actions"
- directory: "/"
+ - package-ecosystem: github-actions
+ directory: /
open-pull-requests-limit: 10
schedule:
- interval: "daily"
- time: "07:00"
- timezone: "Europe/Berlin"
+ interval: daily
+ time: '07:00'
+ timezone: Europe/Berlin
assignees:
- ffried
reviewers:
- ffried
- - package-ecosystem: "github-actions"
- directory: ".github/actions/generate-action-code"
+
+ - package-ecosystem: github-actions
+ directory: .github/actions/generate-action-code
open-pull-requests-limit: 10
schedule:
- interval: "daily"
- time: "07:00"
- timezone: "Europe/Berlin"
+ interval: daily
+ time: '07:00'
+ timezone: Europe/Berlin
assignees:
- ffried
reviewers:
- ffried
- - package-ecosystem: "npm"
- directory: "/"
+
+ - package-ecosystem: npm
+ directory: /
open-pull-requests-limit: 10
schedule:
- interval: "daily"
- time: "07:00"
- timezone: "Europe/Berlin"
+ interval: daily
+ time: '07:00'
+ timezone: Europe/Berlin
assignees:
- ffried
reviewers:
diff --git a/README.md b/README.md
index b38de59..d1ae129 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,10 @@ Note that this action needs to run on macOS. All other platforms will fail!
See [action.yml](action.yml) for an overview of all inputs.
For more information about the various inputs, also see `man xcodebuild`.
+**Notes:**
+- If you are missing an input, you can pass them in the `build-settings` input. These will be passed along to `xcodebuild` as is.
+- If an enum input validation fails because you use a value that isn't yet known to this action, set `disable-enum-validation` to `true`.
+
## Outputs
### `unprocessed-command`
diff --git a/action.yml b/action.yml
index d2fd690..e1b3036 100644
--- a/action.yml
+++ b/action.yml
@@ -17,6 +17,9 @@ inputs:
target:
description: The target to build. See also `xcodebuild`'s `-target`.
required: false
+ all-targets:
+ description: If `true`, all targets will be built. See also `xcodebuild`'s `-allTargets`.
+ required: false
destination:
description: The destination specifier to build. See also `xcodebuild`'s `-destination`.
required: false
@@ -32,6 +35,9 @@ inputs:
xcconfig:
description: The path to an xcconfig file with build settings overrides. See also `xcodebuild`'s `-xcconfig`.
required: false
+ toolchain:
+ description: The toolchain identifier or name to use for building. See also `xcodebuild`'s `-toolchain`.
+ required: false
jobs:
description: The number of jobs to use for building. See also `xcodebuild`'s `-jobs`.
required: false
@@ -80,6 +86,12 @@ inputs:
derived-data-path:
description: The path that should be used for derived data. See also `xcodebuild`'s `-derivedDataPath`.
required: false
+ default-package-registry-url:
+ description: The default package registry URL. See also `xcodebuild`'s `-defaultPackageRegistryURL`.
+ required: false
+ package-dependency-scm-to-registry-transformation:
+ description: The package dependency SCM to registry transformation. See also `xcodebuild`'s `-packageDependencySCMToRegistryTransformation`.
+ required: false
disable-package-repository-cache:
description: Whether the package repository cache should be disabled. See also `xcodebuild`'s `-disablePackageRepositoryCache`.
required: false
@@ -95,12 +107,24 @@ inputs:
skip-macro-validation:
description: Whether macro validation should be skipped. See also `xcodebuild`'s `-skipMacroValidation`.
required: false
+ package-fingerprint-policy:
+ description: The package fingerprint checking policy. See also `xcodebuild`'s `-packageFingerprintPolicy`.
+ required: false
+ package-signing-entity-policy:
+ description: The package signing entity policy. See also `xcodebuild`'s `-packageSigningEntityPolicy`.
+ required: false
xcroot:
description: The path to a .xcroot to use for building and/or testing. See also `xcodebuild`'s `-xcroot`.
required: false
xctestrun:
description: The path to a test run specification. See also `xcodebuild`'s `-xctestrun`.
required: false
+ test-language:
+ description: The language to use for testing. See also `xcodebuild`'s `-testLanguage`.
+ required: false
+ test-region:
+ description: The region to use for testing. See also `xcodebuild`'s `-testRegion`.
+ required: false
test-plan:
description: The name of the test plan associated with the scheme to use for testing. See also `xcodebuild`'s `-testPlan`.
required: false
@@ -110,6 +134,21 @@ inputs:
skip-testing:
description: A (line-separated) list of tests to skip. See also `xcodebuild`'s `-skip-testing`.
required: false
+ only-test-configuration:
+ description: A (line-separated) list of test configurations to run. See also `xcodebuild`'s `-only-test-configuration`.
+ required: false
+ skip-test-configuration:
+ description: A (line-separated) list of test configurations to skip. See also `xcodebuild`'s `-skip-test-configuration`.
+ required: false
+ test-iterations:
+ description: The number of iterations to run the tests. See also `xcodebuild`'s `-test-iterations`.
+ required: false
+ retry-tests-on-failure:
+ description: Whether tests should be retried on failure. See also `xcodebuild`'s `-retry-tests-on-failure`.
+ required: false
+ run-tests-until-failure:
+ description: Whether tests should be run until failure. See also `xcodebuild`'s `-run-tests-until-failure`.
+ required: false
skip-unavailable-actions:
description: Whether unavailable actions should be skipped instead of failing the execution. See also `xcodebuild`'s `-skipUnavailableActions`.
required: false
@@ -119,6 +158,21 @@ inputs:
allow-provisioning-device-registration:
description: Whether provisioning device registrations are allowed. See also `xcodebuild`'s `-allowProvisioningDeviceRegistration`.
required: false
+ export-notarized-app:
+ description: Whether the app should be exported notarized. See also `xcodebuild`'s `-exportNotarizedApp`.
+ required: false
+ export-options-plist:
+ description: The path to an export options plist. See also `xcodebuild`'s `-exportOptionsPlist`.
+ required: false
+ export-archive:
+ description: Whether an archive should be exported. See also `xcodebuild`'s `-exportArchive`.
+ required: false
+ archive-path:
+ description: The path to where archives are created. See also `xcodebuild`'s `-archivePath`.
+ required: false
+ create-xcframework:
+ description: Whether an xcframework should be created. See also `xcodebuild`'s `-create-xcframework`.
+ required: false
build-settings:
description: Arbitrary, space separated build settings (e.g. PLATFORM_NAME=iphonesimulator).
required: false
@@ -130,6 +184,10 @@ inputs:
description: The output formatter to use (e.g. xcpretty, xcbeautify, ...). The xcodebuild output will be piped into this formatter.
required: false
default: 'xcpretty --color'
+ disable-enum-input-validation:
+ description: Whether the input validation for enums should be disabled. Usually only needed if new values are added to the enums in the future.
+ required: false
+ default: 'false'
dry-run:
description: ' Whether the commands should only be composed and not actually run. Only used in test.'
required: false
diff --git a/package-lock.json b/package-lock.json
index bede6c0..400806e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,7 @@
},
"devDependencies": {
"@tsconfig/node20": "^20.1.4",
- "@types/node": "^20.6.2",
+ "@types/node": "^20.11.30",
"@vercel/ncc": "^0.38.1",
"typescript": "^5.4.3"
},
@@ -45,10 +45,13 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "20.6.2",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz",
- "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==",
- "dev": true
+ "version": "20.11.30",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz",
+ "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
},
"node_modules/@vercel/ncc": {
"version": "0.38.1",
@@ -80,6 +83,12 @@
"node": ">=14.17"
}
},
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
diff --git a/package.json b/package.json
index b306e10..c1e89a4 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
},
"devDependencies": {
"@tsconfig/node20": "^20.1.4",
- "@types/node": "^20.6.2",
+ "@types/node": "^20.11.30",
"@vercel/ncc": "^0.38.1",
"typescript": "^5.4.3"
}
diff --git a/src/main.ts b/src/main.ts
index bd80c31..27479c9 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -60,7 +60,7 @@ function argumentValueString(value: ICommandArgumentValue,
function _cmdEscape(str: string): string {
return str.replace(/((?!\\).|^)( )/g, `$1\\ `);
}
- let strValue = useResolvedValue ? value.resolvedValue : value.originalValue
+ let strValue = useResolvedValue ? value.resolvedValue : value.originalValue;
return escapeValue ? _cmdEscape(strValue) : strValue;
}
@@ -140,6 +140,8 @@ async function main() {
}
const scheme = core.getInput('scheme', { required: !!workspace || !!spmPackage });
+ const disableEnumInputValidation = core.getBooleanInput('disable-enum-input-validation');
+
function _pushArg(name: string, value?: ICommandArgumentValue) {
xcodebuildArgs.push({ name: `-${name}`, value: value });
}
@@ -156,45 +158,64 @@ async function main() {
_pushArg(name, { originalValue: value, resolvedValue: processedValue });
}
- function _addInputArg(inputName: string, argName?: string, opts?: { isPath?: boolean, isList?: boolean }) {
- if (opts?.isList) {
+ function _addInputArg(inputName: string,
+ argName?: string,
+ opts?: { isPath?: boolean, isList?: boolean, validValues?: string[] }): boolean {
+ if (opts?.isList) { // opts is guaranteed to be set in this branch.
let values = core.getMultilineInput(inputName);
- if (values)
- values.forEach(value => _pushArgWithValue(argName ?? inputName, value, {
- isPath: opts?.isPath,
+ if (!values) return false;
+ for (const value of values) {
+ if (!disableEnumInputValidation && opts.validValues && !opts.validValues.includes(value))
+ throw new Error(`Invalid value for ${inputName}: ${value}! Valid values: ${opts.validValues.join(', ')}`);
+ _pushArgWithValue(argName ?? inputName, value, {
+ isPath: opts.isPath,
skipEmptyValues: true,
- }));
+ });
+ }
+ return values.length > 0;
} else {
let value = core.getInput(inputName);
- if (value)
- _pushArgWithValue(argName ?? inputName, value, {
- isPath: opts?.isPath,
- skipEmptyValues: false,
- })
+ if (!value) return false;
+ if (!disableEnumInputValidation && opts?.validValues && !opts.validValues.includes(value))
+ throw new Error(`Invalid value for ${inputName}: ${value}! Valid values: ${opts.validValues.join(', ')}`);
+ _pushArgWithValue(argName ?? inputName, value, {
+ isPath: opts?.isPath,
+ skipEmptyValues: false,
+ });
+ return true;
}
}
- function addInputArg(inputName: string, argName?: string) {
- _addInputArg(inputName, argName);
+ function addInputArg(inputName: string, argName?: string): boolean {
+ return _addInputArg(inputName, argName);
}
- function addPathArg(inputName: string, argName?: string) {
- _addInputArg(inputName, argName, { isPath: true });
+ function addPathArg(inputName: string, argName?: string): boolean {
+ return _addInputArg(inputName, argName, { isPath: true });
}
- function addListArg(inputName: string, argName?: string) {
- _addInputArg(inputName, argName, { isList: true });
+ function addListArg(inputName: string, argName?: string): boolean {
+ return _addInputArg(inputName, argName, { isList: true });
}
- function addBoolArg(inputName: string, argName?: string) {
+ function addEnumArg(inputName: string, validValues: string[], argName?: string): boolean {
+ return _addInputArg(inputName, argName, { validValues });
+ }
+
+ function addBoolArg(inputName: string, argName?: string): boolean {
const value = core.getInput(inputName);
- if (value?.length)
- _pushArgWithValue(argName ?? inputName, core.getBooleanInput(inputName) ? 'YES' : 'NO')
+ const hasValue = !!value && value.length > 0;
+ if (hasValue)
+ _pushArgWithValue(argName ?? inputName, core.getBooleanInput(inputName) ? 'YES' : 'NO');
+ return hasValue;
}
- function addFlagArg(inputName: string, argName?: string) {
- if (core.getInput(inputName).length && core.getBooleanInput(inputName))
+ function addFlagArg(inputName: string, argName?: string): boolean {
+ const value = core.getInput(inputName);
+ const hasValue = !!value && value.length > 0;
+ if (hasValue && core.getBooleanInput(inputName))
_pushArg(argName ?? inputName);
+ return hasValue;
}
if (workspace) {
@@ -204,12 +225,14 @@ async function main() {
}
if (scheme) _pushArgWithValue('scheme', scheme);
- addInputArg('target');
+ if (addInputArg('target') && addFlagArg('all-targets', 'alltargets'))
+ throw new Error('`target` and `all-targets` are mutually exclusive!');
addInputArg('destination');
addInputArg('configuration');
addInputArg('sdk');
addInputArg('arch');
addPathArg('xcconfig');
+ addInputArg('toolchain');
addInputArg('jobs');
addFlagArg('parallelize-targets', 'parallelizeTargets');
addBoolArg('enable-code-coverage', 'enableCodeCoverage');
@@ -226,19 +249,37 @@ async function main() {
addPathArg('cloned-source-packages-path', 'clonedSourcePackagesDirPath');
addPathArg('package-cache-path', 'packageCachePath');
addPathArg('derived-data-path', 'derivedDataPath');
+ addInputArg('default-package-registry-url', 'defaultPackageRegistryURL');
+ addEnumArg('package-dependency-scm-to-registry-transformation',
+ ['none', 'useRegistryIdentity', 'useRegistryIdentityAndSources'],
+ 'packageDependencySCMToRegistryTransformation');
addFlagArg('disable-package-repository-cache', 'disablePackageRepositoryCache');
addFlagArg('disable-automatic-package-resolution', 'disableAutomaticPackageResolution');
addFlagArg('skip-package-updates', 'skipPackageUpdates');
addFlagArg('skip-package-plugin-validation', 'skipPackagePluginValidation');
addFlagArg('skip-macro-validation', 'skipMacroValidation');
+ addEnumArg('package-fingerprint-policy', ['warn', 'strict'], 'packageFingerprintPolicy');
+ addEnumArg('package-signing-entity-policy', ['warn', 'strict'], 'packageSigningEntityPolicy');
addPathArg('xcroot');
addPathArg('xctestrun');
+ addInputArg('test-language', 'testLanguage');
+ addInputArg('test-region', 'testRegion');
addInputArg('test-plan', 'testPlan');
addListArg('only-testing');
addListArg('skip-testing');
+ addListArg('only-test-configuration');
+ addListArg('skip-test-configuration');
+ addInputArg('test-iterations');
+ addFlagArg('retry-tests-on-failure');
+ addFlagArg('run-tests-until-failure');
addFlagArg('skip-unavailable-actions', 'skipUnavailableActions');
addFlagArg('allow-provisioning-updates', 'allowProvisioningUpdates');
addFlagArg('allow-provisioning-device-registration', 'allowProvisioningDeviceRegistration');
+ addFlagArg('export-notarized-app', 'exportNotarizedApp');
+ addPathArg('export-options-plist', 'exportOptionsPlist');
+ addFlagArg('export-archive', 'exportArchive');
+ addPathArg('archive-path', 'archivePath');
+ addFlagArg('create-xcframework');
const buildSettings = core.getInput('build-settings');
if (buildSettings)
@@ -285,7 +326,7 @@ async function main() {
...inv,
';',
'popd',
- ]
+ ];
}
unprocessedInvocation = _combinedInv(unprocessedInvocation, false);
processedInvocation = _combinedInv(processedInvocation, true);