diff --git a/.github/.eslintrc.js b/.github/.eslintrc.js
index d1f75405f7a2..41fc57fb9829 100644
--- a/.github/.eslintrc.js
+++ b/.github/.eslintrc.js
@@ -7,5 +7,6 @@ module.exports = {
'no-await-in-loop': 'off',
'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'],
'no-continue': 'off',
+ 'no-restricted-imports': 'off',
},
};
diff --git a/.github/actions/javascript/authorChecklist/index.js b/.github/actions/javascript/authorChecklist/index.js
index 9b4b5dac69f5..612a2457d630 100644
--- a/.github/actions/javascript/authorChecklist/index.js
+++ b/.github/actions/javascript/authorChecklist/index.js
@@ -17017,6 +17017,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js
index cfbe438022a0..7bdbafc0b722 100644
--- a/.github/actions/javascript/awaitStagingDeploys/index.js
+++ b/.github/actions/javascript/awaitStagingDeploys/index.js
@@ -12258,6 +12258,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/checkDeployBlockers/index.js b/.github/actions/javascript/checkDeployBlockers/index.js
index e0cb48b0a9c4..74cd1509fbfa 100644
--- a/.github/actions/javascript/checkDeployBlockers/index.js
+++ b/.github/actions/javascript/checkDeployBlockers/index.js
@@ -11541,6 +11541,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js
index d9fa61b08448..6e7237e7cd93 100644
--- a/.github/actions/javascript/createOrUpdateStagingDeploy/index.js
+++ b/.github/actions/javascript/createOrUpdateStagingDeploy/index.js
@@ -14353,6 +14353,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/getArtifactInfo/index.js b/.github/actions/javascript/getArtifactInfo/index.js
index c1cca94b6cbd..82bf90ef6d2b 100644
--- a/.github/actions/javascript/getArtifactInfo/index.js
+++ b/.github/actions/javascript/getArtifactInfo/index.js
@@ -11502,6 +11502,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts b/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts
index c15036c93232..b9d01702e66e 100644
--- a/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts
+++ b/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts
@@ -19,26 +19,32 @@ async function run() {
// eslint-disable-next-line @typescript-eslint/naming-convention
workflow_id: 'platformDeploy.yml',
status: 'completed',
- event: isProductionDeploy ? 'release' : 'push',
})
).data.workflow_runs
// Note: we filter out cancelled runs instead of looking only for success runs
// because if a build fails on even one platform, then it will have the status 'failure'
.filter((workflowRun) => workflowRun.conclusion !== 'cancelled');
- // Find the most recent deploy workflow for which at least one of the build jobs finished successfully.
+ // Find the most recent deploy workflow targeting the correct environment, for which at least one of the build jobs finished successfully
let lastSuccessfulDeploy = completedDeploys.shift();
while (
- lastSuccessfulDeploy &&
- !(
- await GithubUtils.octokit.actions.listJobsForWorkflowRun({
+ lastSuccessfulDeploy?.head_branch &&
+ ((
+ await GithubUtils.octokit.repos.getReleaseByTag({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
- // eslint-disable-next-line @typescript-eslint/naming-convention
- run_id: lastSuccessfulDeploy.id,
- filter: 'latest',
+ tag: lastSuccessfulDeploy.head_branch,
})
- ).data.jobs.some((job) => job.name.startsWith('Build and deploy') && job.conclusion === 'success')
+ ).data.prerelease === isProductionDeploy ||
+ !(
+ await GithubUtils.octokit.actions.listJobsForWorkflowRun({
+ owner: github.context.repo.owner,
+ repo: github.context.repo.repo,
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ run_id: lastSuccessfulDeploy.id,
+ filter: 'latest',
+ })
+ ).data.jobs.some((job) => job.name.startsWith('Build and deploy') && job.conclusion === 'success'))
) {
console.log(`Deploy was not a success: ${lastSuccessfulDeploy.html_url}, looking at the next one`);
lastSuccessfulDeploy = completedDeploys.shift();
diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js
index 3173dd2358eb..05ae086fcc24 100644
--- a/.github/actions/javascript/getDeployPullRequestList/index.js
+++ b/.github/actions/javascript/getDeployPullRequestList/index.js
@@ -11514,21 +11514,25 @@ async function run() {
// eslint-disable-next-line @typescript-eslint/naming-convention
workflow_id: 'platformDeploy.yml',
status: 'completed',
- event: isProductionDeploy ? 'release' : 'push',
})).data.workflow_runs
// Note: we filter out cancelled runs instead of looking only for success runs
// because if a build fails on even one platform, then it will have the status 'failure'
.filter((workflowRun) => workflowRun.conclusion !== 'cancelled');
- // Find the most recent deploy workflow for which at least one of the build jobs finished successfully.
+ // Find the most recent deploy workflow targeting the correct environment, for which at least one of the build jobs finished successfully
let lastSuccessfulDeploy = completedDeploys.shift();
- while (lastSuccessfulDeploy &&
- !(await GithubUtils_1.default.octokit.actions.listJobsForWorkflowRun({
+ while (lastSuccessfulDeploy?.head_branch &&
+ ((await GithubUtils_1.default.octokit.repos.getReleaseByTag({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
- // eslint-disable-next-line @typescript-eslint/naming-convention
- run_id: lastSuccessfulDeploy.id,
- filter: 'latest',
- })).data.jobs.some((job) => job.name.startsWith('Build and deploy') && job.conclusion === 'success')) {
+ tag: lastSuccessfulDeploy.head_branch,
+ })).data.prerelease === isProductionDeploy ||
+ !(await GithubUtils_1.default.octokit.actions.listJobsForWorkflowRun({
+ owner: github.context.repo.owner,
+ repo: github.context.repo.repo,
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ run_id: lastSuccessfulDeploy.id,
+ filter: 'latest',
+ })).data.jobs.some((job) => job.name.startsWith('Build and deploy') && job.conclusion === 'success'))) {
console.log(`Deploy was not a success: ${lastSuccessfulDeploy.html_url}, looking at the next one`);
lastSuccessfulDeploy = completedDeploys.shift();
}
@@ -11636,6 +11640,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/getPreviousVersion/index.js b/.github/actions/javascript/getPreviousVersion/index.js
index aff2a13da163..7b7ff20ef426 100644
--- a/.github/actions/javascript/getPreviousVersion/index.js
+++ b/.github/actions/javascript/getPreviousVersion/index.js
@@ -2769,6 +2769,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/getPullRequestDetails/index.js b/.github/actions/javascript/getPullRequestDetails/index.js
index f1c2054cca1d..8580842b380c 100644
--- a/.github/actions/javascript/getPullRequestDetails/index.js
+++ b/.github/actions/javascript/getPullRequestDetails/index.js
@@ -11604,6 +11604,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/isStagingDeployLocked/index.js b/.github/actions/javascript/isStagingDeployLocked/index.js
index 19acda9b7474..9e823e8da5ae 100644
--- a/.github/actions/javascript/isStagingDeployLocked/index.js
+++ b/.github/actions/javascript/isStagingDeployLocked/index.js
@@ -11502,6 +11502,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/index.js b/.github/actions/javascript/markPullRequestsAsDeployed/index.js
index 06d569d6fb5a..9f97e4a72d20 100644
--- a/.github/actions/javascript/markPullRequestsAsDeployed/index.js
+++ b/.github/actions/javascript/markPullRequestsAsDeployed/index.js
@@ -6555,6 +6555,1174 @@ function isPlainObject(o) {
exports.isPlainObject = isPlainObject;
+/***/ }),
+
+/***/ 5902:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var hashClear = __nccwpck_require__(1789),
+ hashDelete = __nccwpck_require__(712),
+ hashGet = __nccwpck_require__(5395),
+ hashHas = __nccwpck_require__(5232),
+ hashSet = __nccwpck_require__(7320);
+
+/**
+ * Creates a hash object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+function Hash(entries) {
+ var index = -1,
+ length = entries == null ? 0 : entries.length;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+}
+
+// Add methods to `Hash`.
+Hash.prototype.clear = hashClear;
+Hash.prototype['delete'] = hashDelete;
+Hash.prototype.get = hashGet;
+Hash.prototype.has = hashHas;
+Hash.prototype.set = hashSet;
+
+module.exports = Hash;
+
+
+/***/ }),
+
+/***/ 6608:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var listCacheClear = __nccwpck_require__(9792),
+ listCacheDelete = __nccwpck_require__(7716),
+ listCacheGet = __nccwpck_require__(5789),
+ listCacheHas = __nccwpck_require__(9386),
+ listCacheSet = __nccwpck_require__(7399);
+
+/**
+ * Creates an list cache object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+function ListCache(entries) {
+ var index = -1,
+ length = entries == null ? 0 : entries.length;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+}
+
+// Add methods to `ListCache`.
+ListCache.prototype.clear = listCacheClear;
+ListCache.prototype['delete'] = listCacheDelete;
+ListCache.prototype.get = listCacheGet;
+ListCache.prototype.has = listCacheHas;
+ListCache.prototype.set = listCacheSet;
+
+module.exports = ListCache;
+
+
+/***/ }),
+
+/***/ 881:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var getNative = __nccwpck_require__(4479),
+ root = __nccwpck_require__(9882);
+
+/* Built-in method references that are verified to be native. */
+var Map = getNative(root, 'Map');
+
+module.exports = Map;
+
+
+/***/ }),
+
+/***/ 938:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var mapCacheClear = __nccwpck_require__(1610),
+ mapCacheDelete = __nccwpck_require__(6657),
+ mapCacheGet = __nccwpck_require__(1372),
+ mapCacheHas = __nccwpck_require__(609),
+ mapCacheSet = __nccwpck_require__(5582);
+
+/**
+ * Creates a map cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+function MapCache(entries) {
+ var index = -1,
+ length = entries == null ? 0 : entries.length;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+}
+
+// Add methods to `MapCache`.
+MapCache.prototype.clear = mapCacheClear;
+MapCache.prototype['delete'] = mapCacheDelete;
+MapCache.prototype.get = mapCacheGet;
+MapCache.prototype.has = mapCacheHas;
+MapCache.prototype.set = mapCacheSet;
+
+module.exports = MapCache;
+
+
+/***/ }),
+
+/***/ 9213:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var root = __nccwpck_require__(9882);
+
+/** Built-in value references. */
+var Symbol = root.Symbol;
+
+module.exports = Symbol;
+
+
+/***/ }),
+
+/***/ 6752:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var eq = __nccwpck_require__(1901);
+
+/**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+}
+
+module.exports = assocIndexOf;
+
+
+/***/ }),
+
+/***/ 7497:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var Symbol = __nccwpck_require__(9213),
+ getRawTag = __nccwpck_require__(923),
+ objectToString = __nccwpck_require__(4200);
+
+/** `Object#toString` result references. */
+var nullTag = '[object Null]',
+ undefinedTag = '[object Undefined]';
+
+/** Built-in value references. */
+var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+/**
+ * The base implementation of `getTag` without fallbacks for buggy environments.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+function baseGetTag(value) {
+ if (value == null) {
+ return value === undefined ? undefinedTag : nullTag;
+ }
+ return (symToStringTag && symToStringTag in Object(value))
+ ? getRawTag(value)
+ : objectToString(value);
+}
+
+module.exports = baseGetTag;
+
+
+/***/ }),
+
+/***/ 411:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var isFunction = __nccwpck_require__(7799),
+ isMasked = __nccwpck_require__(9058),
+ isObject = __nccwpck_require__(3334),
+ toSource = __nccwpck_require__(6928);
+
+/**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+
+/** Used to detect host constructors (Safari). */
+var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+/** Used for built-in method references. */
+var funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+/** Used to resolve the decompiled source of functions. */
+var funcToString = funcProto.toString;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/** Used to detect if a method is native. */
+var reIsNative = RegExp('^' +
+ funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+);
+
+/**
+ * The base implementation of `_.isNative` without bad shim checks.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function,
+ * else `false`.
+ */
+function baseIsNative(value) {
+ if (!isObject(value) || isMasked(value)) {
+ return false;
+ }
+ var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
+ return pattern.test(toSource(value));
+}
+
+module.exports = baseIsNative;
+
+
+/***/ }),
+
+/***/ 8380:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var root = __nccwpck_require__(9882);
+
+/** Used to detect overreaching core-js shims. */
+var coreJsData = root['__core-js_shared__'];
+
+module.exports = coreJsData;
+
+
+/***/ }),
+
+/***/ 2085:
+/***/ ((module) => {
+
+/** Detect free variable `global` from Node.js. */
+var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+module.exports = freeGlobal;
+
+
+/***/ }),
+
+/***/ 9980:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var isKeyable = __nccwpck_require__(3308);
+
+/**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+function getMapData(map, key) {
+ var data = map.__data__;
+ return isKeyable(key)
+ ? data[typeof key == 'string' ? 'string' : 'hash']
+ : data.map;
+}
+
+module.exports = getMapData;
+
+
+/***/ }),
+
+/***/ 4479:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var baseIsNative = __nccwpck_require__(411),
+ getValue = __nccwpck_require__(3542);
+
+/**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+function getNative(object, key) {
+ var value = getValue(object, key);
+ return baseIsNative(value) ? value : undefined;
+}
+
+module.exports = getNative;
+
+
+/***/ }),
+
+/***/ 923:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var Symbol = __nccwpck_require__(9213);
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString = objectProto.toString;
+
+/** Built-in value references. */
+var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+/**
+ * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the raw `toStringTag`.
+ */
+function getRawTag(value) {
+ var isOwn = hasOwnProperty.call(value, symToStringTag),
+ tag = value[symToStringTag];
+
+ try {
+ value[symToStringTag] = undefined;
+ var unmasked = true;
+ } catch (e) {}
+
+ var result = nativeObjectToString.call(value);
+ if (unmasked) {
+ if (isOwn) {
+ value[symToStringTag] = tag;
+ } else {
+ delete value[symToStringTag];
+ }
+ }
+ return result;
+}
+
+module.exports = getRawTag;
+
+
+/***/ }),
+
+/***/ 3542:
+/***/ ((module) => {
+
+/**
+ * Gets the value at `key` of `object`.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+function getValue(object, key) {
+ return object == null ? undefined : object[key];
+}
+
+module.exports = getValue;
+
+
+/***/ }),
+
+/***/ 1789:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var nativeCreate = __nccwpck_require__(3041);
+
+/**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+function hashClear() {
+ this.__data__ = nativeCreate ? nativeCreate(null) : {};
+ this.size = 0;
+}
+
+module.exports = hashClear;
+
+
+/***/ }),
+
+/***/ 712:
+/***/ ((module) => {
+
+/**
+ * Removes `key` and its value from the hash.
+ *
+ * @private
+ * @name delete
+ * @memberOf Hash
+ * @param {Object} hash The hash to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+function hashDelete(key) {
+ var result = this.has(key) && delete this.__data__[key];
+ this.size -= result ? 1 : 0;
+ return result;
+}
+
+module.exports = hashDelete;
+
+
+/***/ }),
+
+/***/ 5395:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var nativeCreate = __nccwpck_require__(3041);
+
+/** Used to stand-in for `undefined` hash values. */
+var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Gets the hash value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Hash
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+function hashGet(key) {
+ var data = this.__data__;
+ if (nativeCreate) {
+ var result = data[key];
+ return result === HASH_UNDEFINED ? undefined : result;
+ }
+ return hasOwnProperty.call(data, key) ? data[key] : undefined;
+}
+
+module.exports = hashGet;
+
+
+/***/ }),
+
+/***/ 5232:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var nativeCreate = __nccwpck_require__(3041);
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Checks if a hash value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Hash
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+function hashHas(key) {
+ var data = this.__data__;
+ return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
+}
+
+module.exports = hashHas;
+
+
+/***/ }),
+
+/***/ 7320:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var nativeCreate = __nccwpck_require__(3041);
+
+/** Used to stand-in for `undefined` hash values. */
+var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+/**
+ * Sets the hash `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Hash
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the hash instance.
+ */
+function hashSet(key, value) {
+ var data = this.__data__;
+ this.size += this.has(key) ? 0 : 1;
+ data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+ return this;
+}
+
+module.exports = hashSet;
+
+
+/***/ }),
+
+/***/ 3308:
+/***/ ((module) => {
+
+/**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+function isKeyable(value) {
+ var type = typeof value;
+ return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+ ? (value !== '__proto__')
+ : (value === null);
+}
+
+module.exports = isKeyable;
+
+
+/***/ }),
+
+/***/ 9058:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var coreJsData = __nccwpck_require__(8380);
+
+/** Used to detect methods masquerading as native. */
+var maskSrcKey = (function() {
+ var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+ return uid ? ('Symbol(src)_1.' + uid) : '';
+}());
+
+/**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+function isMasked(func) {
+ return !!maskSrcKey && (maskSrcKey in func);
+}
+
+module.exports = isMasked;
+
+
+/***/ }),
+
+/***/ 9792:
+/***/ ((module) => {
+
+/**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+function listCacheClear() {
+ this.__data__ = [];
+ this.size = 0;
+}
+
+module.exports = listCacheClear;
+
+
+/***/ }),
+
+/***/ 7716:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var assocIndexOf = __nccwpck_require__(6752);
+
+/** Used for built-in method references. */
+var arrayProto = Array.prototype;
+
+/** Built-in value references. */
+var splice = arrayProto.splice;
+
+/**
+ * Removes `key` and its value from the list cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf ListCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+function listCacheDelete(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = data.length - 1;
+ if (index == lastIndex) {
+ data.pop();
+ } else {
+ splice.call(data, index, 1);
+ }
+ --this.size;
+ return true;
+}
+
+module.exports = listCacheDelete;
+
+
+/***/ }),
+
+/***/ 5789:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var assocIndexOf = __nccwpck_require__(6752);
+
+/**
+ * Gets the list cache value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf ListCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+function listCacheGet(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ return index < 0 ? undefined : data[index][1];
+}
+
+module.exports = listCacheGet;
+
+
+/***/ }),
+
+/***/ 9386:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var assocIndexOf = __nccwpck_require__(6752);
+
+/**
+ * Checks if a list cache value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf ListCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+function listCacheHas(key) {
+ return assocIndexOf(this.__data__, key) > -1;
+}
+
+module.exports = listCacheHas;
+
+
+/***/ }),
+
+/***/ 7399:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var assocIndexOf = __nccwpck_require__(6752);
+
+/**
+ * Sets the list cache `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf ListCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the list cache instance.
+ */
+function listCacheSet(key, value) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ ++this.size;
+ data.push([key, value]);
+ } else {
+ data[index][1] = value;
+ }
+ return this;
+}
+
+module.exports = listCacheSet;
+
+
+/***/ }),
+
+/***/ 1610:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var Hash = __nccwpck_require__(5902),
+ ListCache = __nccwpck_require__(6608),
+ Map = __nccwpck_require__(881);
+
+/**
+ * Removes all key-value entries from the map.
+ *
+ * @private
+ * @name clear
+ * @memberOf MapCache
+ */
+function mapCacheClear() {
+ this.size = 0;
+ this.__data__ = {
+ 'hash': new Hash,
+ 'map': new (Map || ListCache),
+ 'string': new Hash
+ };
+}
+
+module.exports = mapCacheClear;
+
+
+/***/ }),
+
+/***/ 6657:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var getMapData = __nccwpck_require__(9980);
+
+/**
+ * Removes `key` and its value from the map.
+ *
+ * @private
+ * @name delete
+ * @memberOf MapCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+function mapCacheDelete(key) {
+ var result = getMapData(this, key)['delete'](key);
+ this.size -= result ? 1 : 0;
+ return result;
+}
+
+module.exports = mapCacheDelete;
+
+
+/***/ }),
+
+/***/ 1372:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var getMapData = __nccwpck_require__(9980);
+
+/**
+ * Gets the map value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf MapCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+function mapCacheGet(key) {
+ return getMapData(this, key).get(key);
+}
+
+module.exports = mapCacheGet;
+
+
+/***/ }),
+
+/***/ 609:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var getMapData = __nccwpck_require__(9980);
+
+/**
+ * Checks if a map value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf MapCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+function mapCacheHas(key) {
+ return getMapData(this, key).has(key);
+}
+
+module.exports = mapCacheHas;
+
+
+/***/ }),
+
+/***/ 5582:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var getMapData = __nccwpck_require__(9980);
+
+/**
+ * Sets the map `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf MapCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the map cache instance.
+ */
+function mapCacheSet(key, value) {
+ var data = getMapData(this, key),
+ size = data.size;
+
+ data.set(key, value);
+ this.size += data.size == size ? 0 : 1;
+ return this;
+}
+
+module.exports = mapCacheSet;
+
+
+/***/ }),
+
+/***/ 3041:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var getNative = __nccwpck_require__(4479);
+
+/* Built-in method references that are verified to be native. */
+var nativeCreate = getNative(Object, 'create');
+
+module.exports = nativeCreate;
+
+
+/***/ }),
+
+/***/ 4200:
+/***/ ((module) => {
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString = objectProto.toString;
+
+/**
+ * Converts `value` to a string using `Object.prototype.toString`.
+ *
+ * @private
+ * @param {*} value The value to convert.
+ * @returns {string} Returns the converted string.
+ */
+function objectToString(value) {
+ return nativeObjectToString.call(value);
+}
+
+module.exports = objectToString;
+
+
+/***/ }),
+
+/***/ 9882:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var freeGlobal = __nccwpck_require__(2085);
+
+/** Detect free variable `self`. */
+var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+/** Used as a reference to the global object. */
+var root = freeGlobal || freeSelf || Function('return this')();
+
+module.exports = root;
+
+
+/***/ }),
+
+/***/ 6928:
+/***/ ((module) => {
+
+/** Used for built-in method references. */
+var funcProto = Function.prototype;
+
+/** Used to resolve the decompiled source of functions. */
+var funcToString = funcProto.toString;
+
+/**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to convert.
+ * @returns {string} Returns the source code.
+ */
+function toSource(func) {
+ if (func != null) {
+ try {
+ return funcToString.call(func);
+ } catch (e) {}
+ try {
+ return (func + '');
+ } catch (e) {}
+ }
+ return '';
+}
+
+module.exports = toSource;
+
+
+/***/ }),
+
+/***/ 1901:
+/***/ ((module) => {
+
+/**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+function eq(value, other) {
+ return value === other || (value !== value && other !== other);
+}
+
+module.exports = eq;
+
+
+/***/ }),
+
+/***/ 7799:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var baseGetTag = __nccwpck_require__(7497),
+ isObject = __nccwpck_require__(3334);
+
+/** `Object#toString` result references. */
+var asyncTag = '[object AsyncFunction]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ proxyTag = '[object Proxy]';
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+ if (!isObject(value)) {
+ return false;
+ }
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 9 which returns 'object' for typed arrays and other constructors.
+ var tag = baseGetTag(value);
+ return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
+}
+
+module.exports = isFunction;
+
+
+/***/ }),
+
+/***/ 3334:
+/***/ ((module) => {
+
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+ var type = typeof value;
+ return value != null && (type == 'object' || type == 'function');
+}
+
+module.exports = isObject;
+
+
+/***/ }),
+
+/***/ 9885:
+/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
+
+var MapCache = __nccwpck_require__(938);
+
+/** Error message constants. */
+var FUNC_ERROR_TEXT = 'Expected a function';
+
+/**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided, it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is used as the map cache key. The `func`
+ * is invoked with the `this` binding of the memoized function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the
+ * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
+ * method interface of `clear`, `delete`, `get`, `has`, and `set`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoized function.
+ * @example
+ *
+ * var object = { 'a': 1, 'b': 2 };
+ * var other = { 'c': 3, 'd': 4 };
+ *
+ * var values = _.memoize(_.values);
+ * values(object);
+ * // => [1, 2]
+ *
+ * values(other);
+ * // => [3, 4]
+ *
+ * object.a = 2;
+ * values(object);
+ * // => [1, 2]
+ *
+ * // Modify the result cache.
+ * values.cache.set(object, ['a', 'b']);
+ * values(object);
+ * // => ['a', 'b']
+ *
+ * // Replace `_.memoize.Cache`.
+ * _.memoize.Cache = WeakMap;
+ */
+function memoize(func, resolver) {
+ if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var args = arguments,
+ key = resolver ? resolver.apply(this, args) : args[0],
+ cache = memoized.cache;
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, args);
+ memoized.cache = cache.set(key, result) || cache;
+ return result;
+ };
+ memoized.cache = new (memoize.Cache || MapCache);
+ return memoized;
+}
+
+// Expose `MapCache`.
+memoize.Cache = MapCache;
+
+module.exports = memoize;
+
+
/***/ }),
/***/ 467:
@@ -11500,6 +12668,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
/* eslint-disable @typescript-eslint/naming-convention, import/no-import-module-exports */
const core = __importStar(__nccwpck_require__(2186));
const github_1 = __nccwpck_require__(5438);
+const memoize_1 = __importDefault(__nccwpck_require__(9885));
const ActionUtils = __importStar(__nccwpck_require__(6981));
const CONST_1 = __importDefault(__nccwpck_require__(9873));
const GithubUtils_1 = __importDefault(__nccwpck_require__(9296));
@@ -11535,6 +12704,7 @@ async function commentPR(PR, message) {
}
}
const workflowURL = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
+const getCommit = (0, memoize_1.default)(GithubUtils_1.default.octokit.git.getCommit);
async function run() {
const prList = ActionUtils.getJSONInput('PR_LIST', { required: true }).map((num) => Number.parseInt(num, 10));
const isProd = ActionUtils.getJSONInput('IS_PRODUCTION_DEPLOY', { required: true });
@@ -11573,25 +12743,11 @@ async function run() {
}
return;
}
- // First find out if this is a normal staging deploy or a CP by looking at the commit message on the tag
const { data: recentTags } = await GithubUtils_1.default.octokit.repos.listTags({
owner: CONST_1.default.GITHUB_OWNER,
repo: CONST_1.default.APP_REPO,
per_page: 100,
});
- const currentTag = recentTags.find((tag) => tag.name === version);
- if (!currentTag) {
- const err = `Could not find tag matching ${version}`;
- console.error(err);
- core.setFailed(err);
- return;
- }
- const { data: commit } = await GithubUtils_1.default.octokit.git.getCommit({
- owner: CONST_1.default.GITHUB_OWNER,
- repo: CONST_1.default.APP_REPO,
- commit_sha: currentTag.commit.sha,
- });
- const isCP = /[\S\s]*\(cherry picked from commit .*\)/.test(commit.message);
for (const prNumber of prList) {
/*
* Determine who the deployer for the PR is. The "deployer" for staging deploys is:
@@ -11604,7 +12760,28 @@ async function run() {
repo: CONST_1.default.APP_REPO,
pull_number: prNumber,
});
- const deployer = isCP ? commit.committer.name : pr.merged_by?.login;
+ // Check for the CP Staging label on the issue to see if it was cherry-picked
+ const isCP = pr.labels.some(({ name: labelName }) => labelName === CONST_1.default.LABELS.CP_STAGING);
+ // Determine the deployer. For most PRs it will be whoever merged the PR.
+ // For CPs it will be whoever created the tag for the PR (i.e: whoever triggered the CP)
+ let deployer = pr.merged_by?.login;
+ if (isCP) {
+ for (const tag of recentTags) {
+ const { data: commit } = await getCommit({
+ owner: CONST_1.default.GITHUB_OWNER,
+ repo: CONST_1.default.APP_REPO,
+ commit_sha: tag.commit.sha,
+ });
+ const prNumForCPMergeCommit = commit.message.match(/Merge pull request #(\d+)[\S\s]*\(cherry picked from commit .*\)/);
+ if (prNumForCPMergeCommit?.at(1) === String(prNumber)) {
+ const cpActor = commit.message.match(/.*\(CP triggered by (.*)\)/)?.at(1);
+ if (cpActor) {
+ deployer = cpActor;
+ }
+ break;
+ }
+ }
+ }
const title = pr.title;
const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : '';
await commentPR(prNumber, deployMessage);
@@ -11709,6 +12886,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts b/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts
index 53018cbb035e..71a5c7d5c6ee 100644
--- a/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts
+++ b/.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed.ts
@@ -2,6 +2,7 @@
import * as core from '@actions/core';
import {context} from '@actions/github';
import type {RequestError} from '@octokit/types';
+import memoize from 'lodash/memoize';
import * as ActionUtils from '@github/libs/ActionUtils';
import CONST from '@github/libs/CONST';
import GithubUtils from '@github/libs/GithubUtils';
@@ -42,6 +43,8 @@ async function commentPR(PR: number, message: string) {
const workflowURL = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
+const getCommit = memoize(GithubUtils.octokit.git.getCommit);
+
async function run() {
const prList = (ActionUtils.getJSONInput('PR_LIST', {required: true}) as string[]).map((num) => Number.parseInt(num, 10));
const isProd = ActionUtils.getJSONInput('IS_PRODUCTION_DEPLOY', {required: true}) as boolean;
@@ -88,25 +91,11 @@ async function run() {
return;
}
- // First find out if this is a normal staging deploy or a CP by looking at the commit message on the tag
const {data: recentTags} = await GithubUtils.octokit.repos.listTags({
owner: CONST.GITHUB_OWNER,
repo: CONST.APP_REPO,
per_page: 100,
});
- const currentTag = recentTags.find((tag) => tag.name === version);
- if (!currentTag) {
- const err = `Could not find tag matching ${version}`;
- console.error(err);
- core.setFailed(err);
- return;
- }
- const {data: commit} = await GithubUtils.octokit.git.getCommit({
- owner: CONST.GITHUB_OWNER,
- repo: CONST.APP_REPO,
- commit_sha: currentTag.commit.sha,
- });
- const isCP = /[\S\s]*\(cherry picked from commit .*\)/.test(commit.message);
for (const prNumber of prList) {
/*
@@ -120,7 +109,30 @@ async function run() {
repo: CONST.APP_REPO,
pull_number: prNumber,
});
- const deployer = isCP ? commit.committer.name : pr.merged_by?.login;
+
+ // Check for the CP Staging label on the issue to see if it was cherry-picked
+ const isCP = pr.labels.some(({name: labelName}) => labelName === CONST.LABELS.CP_STAGING);
+
+ // Determine the deployer. For most PRs it will be whoever merged the PR.
+ // For CPs it will be whoever created the tag for the PR (i.e: whoever triggered the CP)
+ let deployer = pr.merged_by?.login;
+ if (isCP) {
+ for (const tag of recentTags) {
+ const {data: commit} = await getCommit({
+ owner: CONST.GITHUB_OWNER,
+ repo: CONST.APP_REPO,
+ commit_sha: tag.commit.sha,
+ });
+ const prNumForCPMergeCommit = commit.message.match(/Merge pull request #(\d+)[\S\s]*\(cherry picked from commit .*\)/);
+ if (prNumForCPMergeCommit?.at(1) === String(prNumber)) {
+ const cpActor = commit.message.match(/.*\(CP triggered by (.*)\)/)?.at(1);
+ if (cpActor) {
+ deployer = cpActor;
+ }
+ break;
+ }
+ }
+ }
const title = pr.title;
const deployMessage = deployer ? getDeployMessage(deployer, isCP ? 'Cherry-picked' : 'Deployed', title) : '';
diff --git a/.github/actions/javascript/postTestBuildComment/index.js b/.github/actions/javascript/postTestBuildComment/index.js
index 6c47718584ce..4f62879a4419 100644
--- a/.github/actions/javascript/postTestBuildComment/index.js
+++ b/.github/actions/javascript/postTestBuildComment/index.js
@@ -11601,6 +11601,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/proposalPoliceComment/index.js b/.github/actions/javascript/proposalPoliceComment/index.js
index 7f7c4ecc38ac..c14b825e1198 100644
--- a/.github/actions/javascript/proposalPoliceComment/index.js
+++ b/.github/actions/javascript/proposalPoliceComment/index.js
@@ -18089,6 +18089,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/reopenIssueWithComment/index.js b/.github/actions/javascript/reopenIssueWithComment/index.js
index 75d40871926c..83131f363ef8 100644
--- a/.github/actions/javascript/reopenIssueWithComment/index.js
+++ b/.github/actions/javascript/reopenIssueWithComment/index.js
@@ -11512,6 +11512,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/reviewerChecklist/index.js b/.github/actions/javascript/reviewerChecklist/index.js
index 0cec1bc183f0..2a0977db8016 100644
--- a/.github/actions/javascript/reviewerChecklist/index.js
+++ b/.github/actions/javascript/reviewerChecklist/index.js
@@ -11604,6 +11604,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/actions/javascript/verifySignedCommits/index.js b/.github/actions/javascript/verifySignedCommits/index.js
index 0d441b9f52d3..49a4341b84af 100644
--- a/.github/actions/javascript/verifySignedCommits/index.js
+++ b/.github/actions/javascript/verifySignedCommits/index.js
@@ -11544,6 +11544,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/libs/CONST.ts b/.github/libs/CONST.ts
index a46f4afc421c..499ff15e5aeb 100644
--- a/.github/libs/CONST.ts
+++ b/.github/libs/CONST.ts
@@ -14,6 +14,7 @@ const CONST = {
DEPLOY_BLOCKER: 'DeployBlockerCash',
INTERNAL_QA: 'InternalQA',
HELP_WANTED: 'Help Wanted',
+ CP_STAGING: 'CP Staging',
},
ACTIONS: {
CREATED: 'created',
diff --git a/.github/scripts/verifyPodfile.sh b/.github/scripts/verifyPodfile.sh
index 2c9a7dee672a..ff67b11c8657 100755
--- a/.github/scripts/verifyPodfile.sh
+++ b/.github/scripts/verifyPodfile.sh
@@ -63,6 +63,7 @@ if ! SPEC_DIRS=$(yq '.["EXTERNAL SOURCES"].[].":path" | select( . == "*node_modu
cleanupAndExit 1
fi
+# Retrieve a list of podspec paths from react-native config
if ! read_lines_into_array PODSPEC_PATHS < <(npx react-native config | jq --raw-output '.dependencies[].platforms.ios.podspecPath | select ( . != null)'); then
error "Error: could not parse podspec paths from react-native config command"
cleanupAndExit 1
diff --git a/.github/workflows/cherryPick.yml b/.github/workflows/cherryPick.yml
index dd2c92e95568..1772d5d309cc 100644
--- a/.github/workflows/cherryPick.yml
+++ b/.github/workflows/cherryPick.yml
@@ -82,7 +82,6 @@ jobs:
id: cherryPick
run: |
echo "Attempting to cherry-pick ${{ steps.getCPMergeCommit.outputs.MERGE_COMMIT_SHA }}"
- git config user.name ${{ github.actor }}
if git cherry-pick -S -x --mainline 1 ${{ steps.getCPMergeCommit.outputs.MERGE_COMMIT_SHA }}; then
echo "🎉 No conflicts! CP was a success, PR can be automerged 🎉"
echo "HAS_CONFLICTS=false" >> "$GITHUB_OUTPUT"
@@ -93,7 +92,7 @@ jobs:
GIT_MERGE_AUTOEDIT=no git cherry-pick --continue
echo "HAS_CONFLICTS=true" >> "$GITHUB_OUTPUT"
fi
- git config user.name OSBotify
+ git commit --amend -m "$(git log -1 --pretty=%B)" -m "(CP triggered by ${{ github.actor }})"
- name: Push changes
run: |
@@ -122,6 +121,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }}
+ - name: Label PR with CP Staging
+ run: gh pr edit ${{ inputs.PULL_REQUEST_NUMBER }} --add-label 'CP Staging'
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+
- name: "Announces a CP failure in the #announce Slack room"
uses: 8398a7/action-slack@v3
if: ${{ failure() }}
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 3f5a8881f244..a20a53678712 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -23,11 +23,11 @@ jobs:
OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }}
OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }}
- - name: Tag version
- run: git tag "$(npm run print-version --silent)"
+ - name: Get current app version
+ run: echo "STAGING_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV"
- - name: 🚀 Push tags to trigger staging deploy 🚀
- run: git push --tags
+ - name: 🚀 Create prerelease to trigger staging deploy 🚀
+ run: gh release create ${{ env.STAGING_VERSION }} --title ${{ env.STAGING_VERSION }} --generate-notes --prerelease
- name: Warn deployers if staging deploy failed
if: ${{ failure() }}
@@ -68,8 +68,8 @@ jobs:
- name: Get current app version
run: echo "PRODUCTION_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV"
- - name: 🚀 Create release to trigger production deploy 🚀
- run: gh release create ${{ env.PRODUCTION_VERSION }} --title ${{ env.PRODUCTION_VERSION }} --generate-notes
+ - name: 🚀 Edit the release to be no longer a prerelease to deploy production 🚀
+ run: gh release edit ${{ env.PRODUCTION_VERSION }} --prerelease=false --latest
env:
GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }}
diff --git a/.github/workflows/deployBlocker.yml b/.github/workflows/deployBlocker.yml
index cb5dc6d28b32..47df9b4285b9 100644
--- a/.github/workflows/deployBlocker.yml
+++ b/.github/workflows/deployBlocker.yml
@@ -39,7 +39,7 @@ jobs:
channel: '#expensify-open-source',
attachments: [{
color: "#DB4545",
- text: '💥 We have found a New Expensify Deploy Blocker, if you have any idea which PR could be causing this, please comment in the issue: <${{ github.event.issue.html_url }}|${{ env.GH_ISSUE_TITLE }}>'
+ text: '💥 New Deploy Blocker: <${{ github.event.issue.html_url }}|${{ env.GH_ISSUE_TITLE }}>. If you have any idea which PR could be causing this, please comment in the issue.'
}]
}
env:
diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml
index 3cb6cd8e5d81..397122930652 100644
--- a/.github/workflows/platformDeploy.yml
+++ b/.github/workflows/platformDeploy.yml
@@ -1,15 +1,12 @@
name: Build and deploy android, desktop, iOS, and web clients
-# This workflow is run when any tag is published
+# This workflow is run when a release or prerelease is created
on:
- push:
- tags:
- - '*'
release:
- types: [created]
+ types: [prereleased, released]
env:
- SHOULD_DEPLOY_PRODUCTION: ${{ github.event_name == 'release' }}
+ SHOULD_DEPLOY_PRODUCTION: ${{ github.event.action == 'released' }}
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}
@@ -36,7 +33,7 @@ jobs:
deployChecklist:
name: Create or update deploy checklist
uses: ./.github/workflows/createDeployChecklist.yml
- if: ${{ github.event_name != 'release' }}
+ if: ${{ github.event.action != 'released' }}
needs: validateActor
secrets: inherit
@@ -226,7 +223,7 @@ jobs:
with:
timeout_minutes: 10
max_attempts: 5
- command: cd ios && bundle exec pod install
+ command: scripts/pod-install.sh
- name: Decrypt AppStore profile
run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output NewApp_AppStore.mobileprovision NewApp_AppStore.mobileprovision.gpg
diff --git a/.github/workflows/preDeploy.yml b/.github/workflows/preDeploy.yml
index 5cfe5e213d2f..e5ccdfa53076 100644
--- a/.github/workflows/preDeploy.yml
+++ b/.github/workflows/preDeploy.yml
@@ -4,7 +4,7 @@ name: Process new code merged to main
on:
push:
branches: [main]
- paths-ignore: [docs/**, contributingGuides/**, jest/**, tests/**, workflow_tests/**]
+ paths-ignore: [docs/**, contributingGuides/**, jest/**, tests/**]
jobs:
typecheck:
diff --git a/.github/workflows/reassurePerformanceTests.yml b/.github/workflows/reassurePerformanceTests.yml
index a0489a52711b..d4a25a63952b 100644
--- a/.github/workflows/reassurePerformanceTests.yml
+++ b/.github/workflows/reassurePerformanceTests.yml
@@ -4,7 +4,7 @@ on:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
- paths-ignore: [docs/**, .github/**, contributingGuides/**, tests/**, workflow_tests/**, '**.md', '**.sh']
+ paths-ignore: [docs/**, .github/**, contributingGuides/**, tests/**, '**.md', '**.sh']
jobs:
perf-tests:
diff --git a/.github/workflows/sendReassurePerfData.yml b/.github/workflows/sendReassurePerfData.yml
index 30a30918f4f6..42d946cece95 100644
--- a/.github/workflows/sendReassurePerfData.yml
+++ b/.github/workflows/sendReassurePerfData.yml
@@ -3,7 +3,7 @@ name: Send Reassure Performance Tests to Graphite
on:
push:
branches: [main]
- paths-ignore: [docs/**, contributingGuides/**, jest/**, workflow_tests/**]
+ paths-ignore: [docs/**, contributingGuides/**, jest/**]
jobs:
perf-tests:
@@ -36,7 +36,7 @@ jobs:
- name: Get and save graphite string
id: saveGraphiteString
uses: ./.github/actions/javascript/getGraphiteString
- with:
+ with:
PR_NUMBER: ${{ steps.getMergedPullRequest.outputs.number }}
- name: Send graphite data
diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml
index 024f5b712a3f..da4225f0e4be 100644
--- a/.github/workflows/testBuild.yml
+++ b/.github/workflows/testBuild.yml
@@ -184,7 +184,7 @@ jobs:
with:
timeout_minutes: 10
max_attempts: 5
- command: cd ios && bundle exec pod install --verbose
+ command: scripts/pod-install.sh
- name: Decrypt AdHoc profile
run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output NewApp_AdHoc.mobileprovision NewApp_AdHoc.mobileprovision.gpg
diff --git a/.github/workflows/testGithubActionsWorkflows.yml b/.github/workflows/testGithubActionsWorkflows.yml
deleted file mode 100644
index f65319f14be4..000000000000
--- a/.github/workflows/testGithubActionsWorkflows.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-name: Test GitHub Actions workflows
-
-on:
- workflow_dispatch:
- workflow_call:
- pull_request:
- types: [opened, reopened, synchronize]
- branches-ignore: [staging, production]
- paths: ['.github/**']
-
-jobs:
- testGHWorkflows:
- if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' || github.event_name == 'workflow_call' }}
- runs-on: ubuntu-latest
- env:
- CI: true
- name: test GitHub Workflows
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Setup Node
- uses: Expensify/App/.github/actions/composite/setupNode@main
-
- - name: Setup Homebrew
- uses: Homebrew/actions/setup-homebrew@master
-
- - name: Login to GitHub Container Regstry
- uses: docker/login-action@v3
- with:
- registry: ghcr.io
- username: OSBotify
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Install Act
- run: brew install act
-
- - name: Set ACT_BINARY
- run: echo "ACT_BINARY=$(which act)" >> "$GITHUB_ENV"
-
- - name: Run tests
- run: npm run workflow-test
diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml
index 3bfc0ed28d1a..32c9e35315b3 100644
--- a/.github/workflows/typecheck.yml
+++ b/.github/workflows/typecheck.yml
@@ -34,7 +34,7 @@ jobs:
# - git diff is used to see the files that were added on this branch
# - gh pr view is used to list files touched by this PR. Git diff may give false positives if the branch isn't up-to-date with main
# - wc counts the words in the result of the intersection
- count_new_js=$(comm -1 -2 <(git diff --name-only --diff-filter=A origin/main HEAD -- 'src/*.js' '__mocks__/*.js' '.storybook/*.js' 'assets/*.js' 'config/*.js' 'desktop/*.js' 'jest/*.js' 'scripts/*.js' 'tests/*.js' 'workflow_tests/*.js' '.github/libs/*.js' '.github/scripts/*.js' ':!src/libs/SearchParser/*.js') <(gh pr view ${{ github.event.pull_request.number }} --json files | jq -r '.files | map(.path) | .[]') | wc -l)
+ count_new_js=$(comm -1 -2 <(git diff --name-only --diff-filter=A origin/main HEAD -- 'src/*.js' '__mocks__/*.js' '.storybook/*.js' 'assets/*.js' 'config/*.js' 'desktop/*.js' 'jest/*.js' 'scripts/*.js' 'tests/*.js' '.github/libs/*.js' '.github/scripts/*.js' ':!src/libs/SearchParser/*.js') <(gh pr view ${{ github.event.pull_request.number }} --json files | jq -r '.files | map(.path) | .[]') | wc -l)
if [ "$count_new_js" -gt "0" ]; then
echo "ERROR: Found new JavaScript files in the project; use TypeScript instead."
exit 1
diff --git a/.gitignore b/.gitignore
index aa6aad4cc429..e33ec43a01fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -110,10 +110,6 @@ tsconfig.tsbuildinfo
# Mock-github
/repo/
-# Workflow test logs
-/workflow_tests/logs/
-/workflow_tests/repo/
-
# Yalc
.yalc
yalc.lock
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 80148aa2b981..9eb4d45f390e 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -108,8 +108,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1009001803
- versionName "9.0.18-3"
+ versionCode 1009001900
+ versionName "9.0.19-0"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
diff --git a/assets/images/cards-and-domains.svg b/assets/images/cards-and-domains.svg
deleted file mode 100644
index a6a3918f6423..000000000000
--- a/assets/images/cards-and-domains.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/contributingGuides/CONTRIBUTING.md b/contributingGuides/CONTRIBUTING.md
index 0ddaafda2d82..61baec9d9f1c 100644
--- a/contributingGuides/CONTRIBUTING.md
+++ b/contributingGuides/CONTRIBUTING.md
@@ -57,7 +57,7 @@ The 168 hours (aka 7 days) will be measured by calculating the time between when
A job could be fixing a bug or working on a new feature. There are two ways you can find a job that you can contribute to:
#### Finding a job that Expensify posted
-This is the most common scenario for contributors. The Expensify team posts new jobs to the Upwork job list [here](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2) (you must be signed in to Upwork to view jobs). Each job in Upwork has a corresponding GitHub issue, which will include instructions to follow. You can also view all open jobs in the Expensify/App GH repository by searching for GH issues with the [`Help Wanted` label](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22). Lastly, you can follow the [@ExpensifyOSS](https://twitter.com/ExpensifyOSS) Twitter account to see a live feed of jobs that are posted.
+This is the most common scenario for contributors. The Expensify team posts new jobs to the Upwork job list [here](https://www.upwork.com/nx/search/jobs/?nbs=1&q=expensify%20react%20native&sort=recency&user_location_match=2) (you must be signed in to Upwork to view jobs). Each job in Upwork has a corresponding GitHub issue, which will include instructions to follow. You can also view all open jobs in the Expensify/App GH repository by searching for GH issues with the [`Help Wanted` label](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22). Lastly, you can follow the [@ExpensifyOSS](https://twitter.com/ExpensifyOSS) Twitter account to see a live feed of jobs that are posted.
>**Note:** Our problem solving approach at Expensify is to focus on high value problems and avoid small optimizations with results that are difficult to measure. We also prefer to identify and solve problems at their root. Given that, please ensure all proposed jobs fix a specific problem in a measurable way with evidence so they are easy to evaluate. Here's an example of a good problem/solution:
>
diff --git a/docs/articles/new-expensify/connections/quickbooks-online/Configure-Quickbooks-Online.md b/docs/articles/new-expensify/connections/quickbooks-online/Configure-Quickbooks-Online.md
index 191d49b046dd..787602337bd2 100644
--- a/docs/articles/new-expensify/connections/quickbooks-online/Configure-Quickbooks-Online.md
+++ b/docs/articles/new-expensify/connections/quickbooks-online/Configure-Quickbooks-Online.md
@@ -9,7 +9,7 @@ description: Coming Soon
When a report exports successfully, a message is posted in the expense’s related chat room:
-
+![Confirmation message posted in the expense chat room](https://help.expensify.com/assets/images/QBO_help_01.png){:width="100%"}
## What happens if I manually export a report that has already been exported?
diff --git a/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md b/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
index 1dbf43c4854f..b132a75e9297 100644
--- a/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
+++ b/docs/articles/new-expensify/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
@@ -17,16 +17,15 @@ An error on a report will prevent it from automatically exporting.
To resolve this, open the expense and make the required changes. Then an admin must manually export the report to QuickBooks Online by clicking on Details > Export:
-
+![Click the Export button found in the Details tab](https://help.expensify.com/assets/images/QBO_help_02.png){:width="100%"}
-
+![Select QuickBooks Online in the Export tab](https://help.expensify.com/assets/images/QBO_help_03.png){:width="100%"}
## Unable to manually export a report
To export a report, it must be in the Approved, Closed, or Reimbursed state. If it is in the Open state, clicking “Export” will lead to an empty page, as the data is not yet available for export:
-
-
+![If the Report is in the Open status, the Not Ready to Export message shows](https://help.expensify.com/assets/images/QBO_help_04.png){:width="100%"}
### How to resolve:
diff --git a/docs/articles/new-expensify/connections/xero/Configure-Xero.md b/docs/articles/new-expensify/connections/xero/Configure-Xero.md
index 0c65db1b4fd9..218e81c98707 100644
--- a/docs/articles/new-expensify/connections/xero/Configure-Xero.md
+++ b/docs/articles/new-expensify/connections/xero/Configure-Xero.md
@@ -3,4 +3,23 @@ title: Configure Xero
description: Coming soon
---
-# Coming soon
+# FAQ
+
+## How do I know if a report successfully exported to Xero?
+
+When a report exports successfully, a message is posted in the related Expensify Chat room.
+
+![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_01.png){:width="100%"}
+
+## What happens if I manually export a report that has already been exported?
+
+When an admin manually exports a report, Expensify will warn them if the report has already been exported. If the admin chooses to export it again, it will create a duplicate report in Xero. You will need to delete the duplicate entries from within Xero.
+
+![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_05.png){:width="100%"}
+
+## What happens to existing reports that have already been approved and reimbursed if I enable Auto Sync?
+
+- If Auto Sync was disabled when your Workspace was linked to Xero, enabling it won’t impact existing reports that haven’t been exported.
+- If a report has been exported and reimbursed via ACH, it will be automatically marked as paid in Xero during the next sync.
+- If a report has been exported and marked as paid in Xero, it will be automatically marked as reimbursed in Expensify during the next sync.
+- If a report has not yet been exported to Xero, it won’t be automatically exported.
diff --git a/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting b/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting
new file mode 100644
index 000000000000..0c69493f3935
--- /dev/null
+++ b/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting
@@ -0,0 +1,37 @@
+---
+title: Xero Troubleshooting
+description: A list of common Xero errors and how to resolve them
+---
+
+## Report won’t automatically export to Xero
+
+If an error occurs during an automatic export to Xero:
+
+- You’ll receive an email detailing the error.
+- The error will appear in the related Workspace Chat, indicated by a red dot next to the report.
+- For auto-sync errors, a message will be posted in the related #admins room. The message contains a link to the workspace’s accounting settings where an explanation for the error appears next to the connection.
+
+An error on a report will prevent it from automatically exporting.
+
+## How to resolve
+
+Open the expense and make the required changes. Then an admin must manually export the report to Xero by clicking the heading at the top of the expense and selecting Export. Then they’ll select Xero.
+
+![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_02.png){:width="100%"}
+
+![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_03.png){:width="100%"}
+
+## Unable to manually export a report
+
+To export a report, it must be in the Approved, Closed, or Reimbursed state. If it is in the Open state, clicking Export will lead to a notification that the data is not yet available for export.
+
+![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_04.png){:width="100%"}
+
+## How to resolve
+
+Open the report and make the required changes:
+
+- If the report is in the Open status, ensure that it is submitted.
+- If the report is in the Processing status, an admin or approver will need to approve it.
+
+Once complete, an admin must manually export the report to Xero by clicking the heading at the top of the expense and selecting Export. Then they’ll select Xero.
diff --git a/docs/articles/new-expensify/expenses-&-payments/Export-expenses.md b/docs/articles/new-expensify/expenses-&-payments/Export-expenses.md
index df112259edbb..f06c436449eb 100644
--- a/docs/articles/new-expensify/expenses-&-payments/Export-expenses.md
+++ b/docs/articles/new-expensify/expenses-&-payments/Export-expenses.md
@@ -10,7 +10,9 @@ To export your expense data to a CSV,
1. Click the **[Search](https://new.expensify.com/search/all?sortBy=date&sortOrder=desc)** tab in the bottom left menu.
2. Select the checkbox to the left of the expenses or reports you wish to export.
- 3. Click **# selected** at the top-right and select **Download**.
+ 3. Click **# selected** at the top-right and select **Download**.
+
+![Select the expenses to download]({{site.url}}/assets/images/Export-Expenses.png){:width="100%"}
The CSV download will save locally to your device with the file naming prefix _“Expensify.”_ This file provides the following data for each expense:
- Date
diff --git a/docs/assets/images/ExpensifyHelp_CreateWorkspace_1.png b/docs/assets/images/ExpensifyHelp_CreateWorkspace_1.png
new file mode 100644
index 000000000000..3dcf92d028ab
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_CreateWorkspace_1.png differ
diff --git a/docs/assets/images/ExpensifyHelp_CreateWorkspace_2.png b/docs/assets/images/ExpensifyHelp_CreateWorkspace_2.png
new file mode 100644
index 000000000000..cafb106e897e
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_CreateWorkspace_2.png differ
diff --git a/docs/assets/images/ExpensifyHelp_CreateWorkspace_3.png b/docs/assets/images/ExpensifyHelp_CreateWorkspace_3.png
new file mode 100644
index 000000000000..08b553857110
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_CreateWorkspace_3.png differ
diff --git a/docs/assets/images/ExpensifyHelp_InviteMembers_1.png b/docs/assets/images/ExpensifyHelp_InviteMembers_1.png
new file mode 100644
index 000000000000..cba73c2ce150
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_InviteMembers_1.png differ
diff --git a/docs/assets/images/ExpensifyHelp_InviteMembers_2.png b/docs/assets/images/ExpensifyHelp_InviteMembers_2.png
new file mode 100644
index 000000000000..e09b8ac5b2b0
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_InviteMembers_2.png differ
diff --git a/docs/assets/images/ExpensifyHelp_InviteMembers_3.png b/docs/assets/images/ExpensifyHelp_InviteMembers_3.png
new file mode 100644
index 000000000000..999e6785ae5f
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_InviteMembers_3.png differ
diff --git a/docs/assets/images/Xero_help_01.png b/docs/assets/images/Xero_help_01.png
new file mode 100644
index 000000000000..ce05ea83c925
Binary files /dev/null and b/docs/assets/images/Xero_help_01.png differ
diff --git a/docs/assets/images/Xero_help_02.png b/docs/assets/images/Xero_help_02.png
new file mode 100644
index 000000000000..c2d556c7aed0
Binary files /dev/null and b/docs/assets/images/Xero_help_02.png differ
diff --git a/docs/assets/images/Xero_help_03.png b/docs/assets/images/Xero_help_03.png
new file mode 100644
index 000000000000..30616ffd3d64
Binary files /dev/null and b/docs/assets/images/Xero_help_03.png differ
diff --git a/docs/assets/images/Xero_help_04.png b/docs/assets/images/Xero_help_04.png
new file mode 100644
index 000000000000..d0e950d3968a
Binary files /dev/null and b/docs/assets/images/Xero_help_04.png differ
diff --git a/docs/assets/images/Xero_help_05.png b/docs/assets/images/Xero_help_05.png
new file mode 100644
index 000000000000..be65e9c62960
Binary files /dev/null and b/docs/assets/images/Xero_help_05.png differ
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index c1a7e4cd5141..3a62b6e6ad7d 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 9.0.18
+ 9.0.19
CFBundleSignature
????
CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 9.0.18.3
+ 9.0.19.0
FullStory
OrgId
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 247216432c35..edd672a2685c 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 9.0.18
+ 9.0.19
CFBundleSignature
????
CFBundleVersion
- 9.0.18.3
+ 9.0.19.0
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 234508f8ab16..b14950632d1d 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -11,9 +11,9 @@
CFBundleName
$(PRODUCT_NAME)
CFBundleShortVersionString
- 9.0.18
+ 9.0.19
CFBundleVersion
- 9.0.18.3
+ 9.0.19.0
NSExtension
NSExtensionPointIdentifier
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 4776096973bc..f5c825e63868 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1871,7 +1871,7 @@ PODS:
- RNGoogleSignin (10.0.1):
- GoogleSignIn (~> 7.0)
- React-Core
- - RNLiveMarkdown (0.1.107):
+ - RNLiveMarkdown (0.1.111):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -1889,9 +1889,9 @@ PODS:
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - RNLiveMarkdown/common (= 0.1.107)
+ - RNLiveMarkdown/common (= 0.1.111)
- Yoga
- - RNLiveMarkdown/common (0.1.107):
+ - RNLiveMarkdown/common (0.1.111):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -2614,7 +2614,7 @@ SPEC CHECKSUMS:
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 74b7b3d06d667ba0bbf41da7718f2607ae0dfe8f
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
- RNLiveMarkdown: f0c641a0bcf5fdea3ec1bb52a64b30ff88d25c1f
+ RNLiveMarkdown: cf2707e6050a3548bde4f66bd752d721f91e8ab6
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
rnmapbox-maps: df8fe93dbd251f25022f4023d31bc04160d4d65c
RNPermissions: d2392b754e67bc14491f5b12588bef2864e783f3
diff --git a/package-lock.json b/package-lock.json
index d57c0e5c1f56..efc714e4b60e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,19 +1,19 @@
{
"name": "new.expensify",
- "version": "9.0.18-3",
+ "version": "9.0.19-0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.0.18-3",
+ "version": "9.0.19-0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@dotlottie/react-player": "^1.6.3",
- "@expensify/react-native-live-markdown": "^0.1.107",
+ "@expensify/react-native-live-markdown": "^0.1.111",
"@expo/metro-runtime": "~3.1.1",
"@formatjs/intl-datetimeformat": "^6.10.0",
"@formatjs/intl-listformat": "^7.2.2",
@@ -55,7 +55,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "2.0.61",
+ "expensify-common": "2.0.64",
"expo": "^50.0.3",
"expo-av": "~13.10.4",
"expo-image": "1.11.0",
@@ -102,7 +102,7 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "2.0.57",
+ "react-native-onyx": "2.0.64",
"react-native-pager-view": "6.2.3",
"react-native-pdf": "6.7.3",
"react-native-performance": "^5.1.0",
@@ -3951,9 +3951,9 @@
}
},
"node_modules/@expensify/react-native-live-markdown": {
- "version": "0.1.107",
- "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.107.tgz",
- "integrity": "sha512-0Yhqo1azCu3cTmzv/KkILZX2yPiyFUZNRx+AdMdT18pMxpqTAuBtFV4HM44rlimmpT3vgwQ1F/0C0AfRAk5dZA==",
+ "version": "0.1.111",
+ "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.111.tgz",
+ "integrity": "sha512-oBRKAGA6Cv+e/D+Z5YduKL7jnD0RJC26SSyUDNMfj11Y3snG0ayi4+XKjVtfbEor9Qb/54WxM8QgEAolxcZ7Xg==",
"workspaces": [
"parser",
"example",
@@ -25942,9 +25942,9 @@
}
},
"node_modules/expensify-common": {
- "version": "2.0.61",
- "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.61.tgz",
- "integrity": "sha512-X900glu2M/m2ggF9xlYlrrihNiwYN6cscYi7WmWp1yGzhGe5VFT+w033doJD1I8JLygtkZoV/xVMY4Porexrxw==",
+ "version": "2.0.64",
+ "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.64.tgz",
+ "integrity": "sha512-+P9+SMPlY799b2l4A3LQ1dle+KvJXcZ01vAFxIDHni4L2Gc1QyddPKLejbwjOrkGqgl3muoR9cwuX/o+QYlYxA==",
"dependencies": {
"awesome-phonenumber": "^5.4.0",
"classnames": "2.5.0",
@@ -37345,16 +37345,16 @@
}
},
"node_modules/react-native-onyx": {
- "version": "2.0.57",
- "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.57.tgz",
- "integrity": "sha512-+/XndOz9kjCvUAYltq6wJbTsPcof+FZz6eFx0cpu/cDEHaYpjNoPWRKhWgWewg5wTYwu7SWl9aYSShRGVUsZWg==",
+ "version": "2.0.64",
+ "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.64.tgz",
+ "integrity": "sha512-RFYiEQBFw9610iTGLXIZ1nQMWuf8VyVEMqiRMLpao75+VnbD6lzh0z7Uuj1eoKMDkjeXJhsPP3rh2MkLnqruug==",
"dependencies": {
"ascii-table": "0.0.9",
"fast-equals": "^4.0.3",
"underscore": "^1.13.6"
},
"engines": {
- "node": ">=20.14.0",
+ "node": ">=20.15.1",
"npm": ">=10.7.0"
},
"peerDependencies": {
diff --git a/package.json b/package.json
index b8a636b02707..e6ac30712a9f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.0.18-3",
+ "version": "9.0.19-0",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
@@ -14,7 +14,7 @@
"clean": "npx react-native clean-project-auto",
"android": "scripts/set-pusher-suffix.sh && npx react-native run-android --mode=developmentDebug --appId=com.expensify.chat.dev --active-arch-only",
"ios": "scripts/set-pusher-suffix.sh && npx react-native run-ios --list-devices --mode=\"DebugDevelopment\" --scheme=\"New Expensify Dev\"",
- "pod-install": "cd ios && bundle exec pod install",
+ "pod-install": "scripts/pod-install.sh",
"ipad": "concurrently \"npx react-native run-ios --simulator=\\\"iPad Pro (12.9-inch) (6th generation)\\\" --mode=\\\"DebugDevelopment\\\" --scheme=\\\"New Expensify Dev\\\"\"",
"ipad-sm": "concurrently \"npx react-native run-ios --simulator=\\\"iPad Pro (11-inch) (4th generation)\\\" --mode=\\\"DebugDevelopment\\\" --scheme=\\\"New Expensify Dev\\\"\"",
"start": "npx react-native start",
@@ -59,8 +59,6 @@
"test:e2e": "ts-node tests/e2e/testRunner.ts --config ./config.local.ts",
"test:e2e:dev": "ts-node tests/e2e/testRunner.ts --config ./config.dev.ts",
"gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh",
- "workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh",
- "workflow-test:generate": "ts-node workflow_tests/utils/preGenerateTest.ts",
"setup-https": "mkcert -install && mkcert -cert-file config/webpack/certificate.pem -key-file config/webpack/key.pem dev.new.expensify.com localhost 127.0.0.1",
"e2e-test-runner-build": "node --max-old-space-size=8192 node_modules/.bin/ncc build tests/e2e/testRunner.ts -o tests/e2e/dist/",
"react-compiler-healthcheck": "react-compiler-healthcheck --verbose",
@@ -71,7 +69,7 @@
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@dotlottie/react-player": "^1.6.3",
- "@expensify/react-native-live-markdown": "^0.1.107",
+ "@expensify/react-native-live-markdown": "^0.1.111",
"@expo/metro-runtime": "~3.1.1",
"@formatjs/intl-datetimeformat": "^6.10.0",
"@formatjs/intl-listformat": "^7.2.2",
@@ -113,7 +111,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "2.0.61",
+ "expensify-common": "2.0.64",
"expo": "^50.0.3",
"expo-av": "~13.10.4",
"expo-image": "1.11.0",
@@ -160,7 +158,7 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "2.0.57",
+ "react-native-onyx": "2.0.64",
"react-native-pager-view": "6.2.3",
"react-native-pdf": "6.7.3",
"react-native-performance": "^5.1.0",
diff --git a/patches/react-native+0.73.4+024+Add-onPaste-to-TextInput.patch b/patches/react-native+0.73.4+024+Add-onPaste-to-TextInput.patch
deleted file mode 100644
index 0107cb7eb660..000000000000
--- a/patches/react-native+0.73.4+024+Add-onPaste-to-TextInput.patch
+++ /dev/null
@@ -1,674 +0,0 @@
-diff --git a/node_modules/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/node_modules/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js
-index 55b770d..6d86715 100644
---- a/node_modules/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js
-+++ b/node_modules/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js
-@@ -464,6 +464,21 @@ export type NativeProps = $ReadOnly<{|
- |}>,
- >,
-
-+ /**
-+ * Invoked when the user performs the paste action.
-+ */
-+ onPaste?: ?DirectEventHandler<
-+ $ReadOnly<{|
-+ target: Int32,
-+ items: $ReadOnlyArray<
-+ $ReadOnly<{|
-+ type: string,
-+ data: string,
-+ |}>,
-+ >,
-+ |}>,
-+ >,
-+
- /**
- * The string that will be rendered before text input has been entered.
- */
-@@ -668,6 +683,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
- topScroll: {
- registrationName: 'onScroll',
- },
-+ topPaste: {
-+ registrationName: 'onPaste',
-+ },
- },
- validAttributes: {
- maxFontSizeMultiplier: true,
-@@ -719,6 +737,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
- textBreakStrategy: true,
- onScroll: true,
- onContentSizeChange: true,
-+ onPaste: true,
- disableFullscreenUI: true,
- includeFontPadding: true,
- fontWeight: true,
-diff --git a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js
-index 8e60c9e..ee383a4 100644
---- a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js
-+++ b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js
-@@ -97,6 +97,9 @@ const RCTTextInputViewConfig = {
- topChangeSync: {
- registrationName: 'onChangeSync',
- },
-+ topPaste: {
-+ registrationName: 'onPaste',
-+ },
- topClear: {
- registrationName: 'onClear',
- },
-@@ -165,6 +168,7 @@ const RCTTextInputViewConfig = {
- onSelectionChange: true,
- onContentSizeChange: true,
- onScroll: true,
-+ onPaste: true,
- onChangeSync: true,
- onKeyPressSync: true,
- onTextInput: true,
-diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts b/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
-index 26a477f..280cbe2 100644
---- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
-+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
-@@ -483,6 +483,16 @@ export interface TextInputTextInputEventData {
- range: {start: number; end: number};
- }
-
-+/**
-+ * @see TextInputProps.onPaste
-+ */
-+export interface TextInputPasteEventData extends TargetedEvent {
-+ items: Array<{
-+ type: string;
-+ data: string;
-+ }>;
-+}
-+
- /**
- * @see https://reactnative.dev/docs/textinput#props
- */
-@@ -811,6 +821,13 @@ export interface TextInputProps
- | ((e: NativeSyntheticEvent) => void)
- | undefined;
-
-+ /**
-+ * Invoked when the user performs the paste action.
-+ */
-+ onPaste?:
-+ | ((e: NativeSyntheticEvent) => void)
-+ | undefined;
-+
- /**
- * The string that will be rendered before text input has been entered
- */
-diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js
-index 9adbfe9..b46437d 100644
---- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js
-+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js
-@@ -94,6 +94,18 @@ export type EditingEvent = SyntheticEvent<
- |}>,
- >;
-
-+export type PasteEvent = SyntheticEvent<
-+ $ReadOnly<{|
-+ target: number,
-+ items: $ReadOnlyArray<
-+ $ReadOnly<{|
-+ type: string,
-+ data: string,
-+ |}>,
-+ >,
-+ |}>,
-+>;
-+
- type DataDetectorTypesType =
- | 'phoneNumber'
- | 'link'
-@@ -796,6 +808,11 @@ export type Props = $ReadOnly<{|
- */
- onScroll?: ?(e: ScrollEvent) => mixed,
-
-+ /**
-+ * Invoked when the user performs the paste action.
-+ */
-+ onPaste?: ?(e: PasteEvent) => mixed,
-+
- /**
- * The string that will be rendered before text input has been entered.
- */
-diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
-index 346acaa..3ab56a2 100644
---- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
-+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
-@@ -132,6 +132,18 @@ export type EditingEvent = SyntheticEvent<
- |}>,
- >;
-
-+export type PasteEvent = SyntheticEvent<
-+ $ReadOnly<{|
-+ target: number,
-+ items: $ReadOnlyArray<
-+ $ReadOnly<{|
-+ type: string,
-+ data: string,
-+ |}>,
-+ >,
-+ |}>,
-+>;
-+
- type DataDetectorTypesType =
- | 'phoneNumber'
- | 'link'
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm
-index 582b49c..ac31cb1 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm
-+++ b/node_modules/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm
-@@ -13,6 +13,9 @@
- #import
- #import
-
-+#import
-+#import
-+
- @implementation RCTUITextView {
- UILabel *_placeholderView;
- UITextView *_detachedTextView;
-@@ -166,7 +169,30 @@ - (void)setSelectedTextRange:(UITextRange *)selectedTextRange notifyDelegate:(BO
- - (void)paste:(id)sender
- {
- _textWasPasted = YES;
-- [super paste:sender];
-+ UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
-+ if (clipboard.hasImages) {
-+ for (NSItemProvider *itemProvider in [clipboard itemProviders]) {
-+ if ([itemProvider canLoadObjectOfClass:[UIImage class]]) {
-+ NSString *identifier = itemProvider.registeredTypeIdentifiers.firstObject;
-+ if (identifier != nil) {
-+ NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType);
-+ NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension);
-+ NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension];
-+ NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
-+ NSURL *fileURL = [NSURL fileURLWithPath:filePath];
-+ NSData *fileData = [clipboard dataForPasteboardType:identifier];
-+ [fileData writeToFile:filePath atomically:YES];
-+ [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]];
-+ }
-+ break;
-+ }
-+ }
-+ } else {
-+ if (clipboard.hasStrings) {
-+ [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string];
-+ }
-+ [super paste:sender];
-+ }
- }
-
- // Turn off scroll animation to fix flaky scrolling.
-@@ -258,6 +284,10 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
- return NO;
- }
-
-+ if (action == @selector(paste:) && [UIPasteboard generalPasteboard].hasImages) {
-+ return YES;
-+ }
-+
- return [super canPerformAction:action withSender:sender];
- }
-
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h
-index 7187177..748c4cc 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h
-+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h
-@@ -36,6 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
- - (void)textInputDidChange;
-
- - (void)textInputDidChangeSelection;
-+- (void)textInputDidPaste:(NSString *)type withData:(NSString *)data;
-
- @optional
-
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h
-index f1c32e6..0ce9dfe 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h
-+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h
-@@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
-
- - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange;
- - (void)selectedTextRangeWasSet;
-+- (void)didPaste:(NSString *)type withData:(NSString *)data;
-
- @end
-
-@@ -30,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
- - (instancetype)initWithTextView:(UITextView *)backedTextInputView;
-
- - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange;
-+- (void)didPaste:(NSString *)type withData:(NSString *)data;
-
- @end
-
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm
-index 9dca6a5..bc43ab8 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm
-+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm
-@@ -147,6 +147,11 @@ - (void)selectedTextRangeWasSet
- [self textFieldProbablyDidChangeSelection];
- }
-
-+- (void)didPaste:(NSString *)type withData:(NSString *)data
-+{
-+ [_backedTextInputView.textInputDelegate textInputDidPaste:type withData:data];
-+}
-+
- #pragma mark - Generalization
-
- - (void)textFieldProbablyDidChangeSelection
-@@ -302,4 +307,9 @@ - (void)textViewProbablyDidChangeSelection
- [_backedTextInputView.textInputDelegate textInputDidChangeSelection];
- }
-
-+- (void)didPaste:(NSString *)type withData:(NSString *)data
-+{
-+ [_backedTextInputView.textInputDelegate textInputDidPaste:type withData:data];
-+}
-+
- @end
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h
-index 209947d..5092dbd 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h
-+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h
-@@ -38,6 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
- @property (nonatomic, copy, nullable) RCTDirectEventBlock onChangeSync;
- @property (nonatomic, copy, nullable) RCTDirectEventBlock onTextInput;
- @property (nonatomic, copy, nullable) RCTDirectEventBlock onScroll;
-+@property (nonatomic, copy, nullable) RCTDirectEventBlock onPaste;
-
- @property (nonatomic, assign) NSInteger mostRecentEventCount;
- @property (nonatomic, assign, readonly) NSInteger nativeEventCount;
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm
-index b0d71dc..2e42fc9 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm
-+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm
-@@ -562,6 +562,26 @@ - (void)textInputDidChangeSelection
- });
- }
-
-+- (void)textInputDidPaste:(NSString *)type withData:(NSString *)data
-+{
-+ if (!_onPaste) {
-+ return;
-+ }
-+
-+ NSMutableArray *items = [NSMutableArray new];
-+ [items addObject:@{
-+ @"type" : type,
-+ @"data" : data,
-+ }];
-+
-+ NSDictionary *payload = @{
-+ @"target" : self.reactTag,
-+ @"items" : items,
-+ };
-+
-+ _onPaste(payload);
-+}
-+
- - (void)updateLocalData
- {
- [self enforceTextAttributesIfNeeded];
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm
-index 4785987..16a9b8e 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm
-+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm
-@@ -67,6 +67,7 @@ @implementation RCTBaseTextInputViewManager {
- RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock)
- RCT_EXPORT_VIEW_PROPERTY(onTextInput, RCTDirectEventBlock)
- RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
-+RCT_EXPORT_VIEW_PROPERTY(onPaste, RCTDirectEventBlock)
-
- RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger)
-
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm
-index 4d0afd9..a6afc7b 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm
-+++ b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm
-@@ -12,6 +12,9 @@
- #import
- #import
-
-+#import
-+#import
-+
- @implementation RCTUITextField {
- RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter;
- NSDictionary *_defaultTextAttributes;
-@@ -139,6 +142,10 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
- return NO;
- }
-
-+ if (action == @selector(paste:) && [UIPasteboard generalPasteboard].hasImages) {
-+ return YES;
-+ }
-+
- return [super canPerformAction:action withSender:sender];
- }
-
-@@ -204,7 +211,30 @@ - (void)setSelectedTextRange:(UITextRange *)selectedTextRange notifyDelegate:(BO
- - (void)paste:(id)sender
- {
- _textWasPasted = YES;
-- [super paste:sender];
-+ UIPasteboard *clipboard = [UIPasteboard generalPasteboard];
-+ if (clipboard.hasImages) {
-+ for (NSItemProvider *itemProvider in [clipboard itemProviders]) {
-+ if ([itemProvider canLoadObjectOfClass:[UIImage class]]) {
-+ NSString *identifier = itemProvider.registeredTypeIdentifiers.firstObject;
-+ if (identifier != nil) {
-+ NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType);
-+ NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension);
-+ NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension];
-+ NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
-+ NSURL *fileURL = [NSURL fileURLWithPath:filePath];
-+ NSData *fileData = [clipboard dataForPasteboardType:identifier];
-+ [fileData writeToFile:filePath atomically:YES];
-+ [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]];
-+ }
-+ break;
-+ }
-+ }
-+ } else {
-+ if (clipboard.hasStrings) {
-+ [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string];
-+ }
-+ [super paste:sender];
-+ }
- }
-
- #pragma mark - Layout
-diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm
-index 70754bf..3ab2c6a 100644
---- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm
-+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm
-@@ -426,6 +426,13 @@ - (void)textInputDidChangeSelection
- }
- }
-
-+- (void)textInputDidPaste:(NSString *)type withData:(NSString *)data
-+{
-+ if (_eventEmitter) {
-+ static_cast(*_eventEmitter).onPaste(std::string([type UTF8String]), std::string([data UTF8String]));
-+ }
-+}
-+
- #pragma mark - RCTBackedTextInputDelegate (UIScrollViewDelegate)
-
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView
-diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java
-new file mode 100644
-index 0000000..62f7e35
---- /dev/null
-+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java
-@@ -0,0 +1,17 @@
-+/*
-+ * Copyright (c) Meta Platforms, Inc. and affiliates.
-+ *
-+ * This source code is licensed under the MIT license found in the
-+ * LICENSE file in the root directory of this source tree.
-+ */
-+
-+package com.facebook.react.views.textinput;
-+
-+/**
-+ * Implement this interface to be informed of paste event in the
-+ * ReactTextEdit This is used by the ReactTextInputManager to forward events
-+ * from the EditText to JS
-+ */
-+interface PasteWatcher {
-+ public void onPaste(String type, String data);
-+}
-\ No newline at end of file
-diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
-index 081f2b8..ff91d47 100644
---- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
-+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
-@@ -9,14 +9,17 @@ package com.facebook.react.views.textinput;
-
- import static com.facebook.react.uimanager.UIManagerHelper.getReactContext;
-
--import android.content.ClipData;
- import android.content.ClipboardManager;
-+import android.content.ClipData;
-+import android.content.ClipDescription;
-+import android.content.ContentResolver;
- import android.content.Context;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.graphics.Typeface;
- import android.graphics.drawable.Drawable;
-+import android.net.Uri;
- import android.os.Build;
- import android.os.Bundle;
- import android.text.Editable;
-@@ -110,6 +113,7 @@ public class ReactEditText extends AppCompatEditText {
- private @Nullable SelectionWatcher mSelectionWatcher;
- private @Nullable ContentSizeWatcher mContentSizeWatcher;
- private @Nullable ScrollWatcher mScrollWatcher;
-+ private @Nullable PasteWatcher mPasteWatcher;
- private InternalKeyListener mKeyListener;
- private boolean mDetectScrollMovement = false;
- private boolean mOnKeyPress = false;
-@@ -153,6 +157,7 @@ public class ReactEditText extends AppCompatEditText {
- mKeyListener = new InternalKeyListener();
- }
- mScrollWatcher = null;
-+ mPasteWatcher = null;
- mTextAttributes = new TextAttributes();
-
- applyTextAttributes();
-@@ -307,10 +312,31 @@ public class ReactEditText extends AppCompatEditText {
- */
- @Override
- public boolean onTextContextMenuItem(int id) {
-- if (id == android.R.id.paste) {
-+ if (id == android.R.id.paste || id == android.R.id.pasteAsPlainText) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- id = android.R.id.pasteAsPlainText;
-- } else {
-+ if (mPasteWatcher != null) {
-+ ClipboardManager clipboardManager =
-+ (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
-+ ClipData clipData = clipboardManager.getPrimaryClip();
-+ String type = null;
-+ String data = null;
-+ if (clipData.getDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
-+ type = ClipDescription.MIMETYPE_TEXT_PLAIN;
-+ data = clipData.getItemAt(0).getText().toString();
-+ } else {
-+ Uri itemUri = clipData.getItemAt(0).getUri();
-+ if (itemUri != null) {
-+ ContentResolver cr = getReactContext(this).getContentResolver();
-+ type = cr.getType(itemUri);
-+ data = itemUri.toString();
-+ }
-+ }
-+ if (type != null && data != null) {
-+ mPasteWatcher.onPaste(type, data);
-+ }
-+ }
-+ } else if (id == android.R.id.paste) {
- ClipboardManager clipboard =
- (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData previousClipData = clipboard.getPrimaryClip();
-@@ -389,6 +415,10 @@ public class ReactEditText extends AppCompatEditText {
- mScrollWatcher = scrollWatcher;
- }
-
-+ public void setPasteWatcher(PasteWatcher pasteWatcher) {
-+ mPasteWatcher = pasteWatcher;
-+ }
-+
- /**
- * Attempt to set a selection or fail silently. Intentionally meant to handle bad inputs.
- * EventCounter is the same one used as with text.
-diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
-index 53e5c49..26dc163 100644
---- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
-+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
-@@ -277,6 +277,9 @@ public class ReactTextInputManager extends BaseViewManager {
-+
-+ private static final String EVENT_NAME = "topPaste";
-+
-+ private String mType;
-+ private String mData;
-+
-+ @Deprecated
-+ public ReactTextInputPasteEvent(int viewId, String type, String data) {
-+ this(ViewUtil.NO_SURFACE_ID, viewId, type, data);
-+ }
-+
-+ public ReactTextInputPasteEvent(int surfaceId, int viewId, String type, String data) {
-+ super(surfaceId, viewId);
-+ mType = type;
-+ mData = data;
-+ }
-+
-+ @Override
-+ public String getEventName() {
-+ return EVENT_NAME;
-+ }
-+
-+ @Override
-+ public boolean canCoalesce() {
-+ return false;
-+ }
-+
-+ @Nullable
-+ @Override
-+ protected WritableMap getEventData() {
-+ WritableMap eventData = Arguments.createMap();
-+
-+ WritableArray items = Arguments.createArray();
-+ WritableMap item = Arguments.createMap();
-+ item.putString("type", mType);
-+ item.putString("data", mData);
-+ items.pushMap(item);
-+
-+ eventData.putArray("items", items);
-+
-+ return eventData;
-+ }
-+}
-\ No newline at end of file
-diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp
-index 1c10b11..de51df9 100644
---- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp
-+++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.cpp
-@@ -198,6 +198,19 @@ void TextInputEventEmitter::onScroll(
- });
- }
-
-+void TextInputEventEmitter::onPaste(const std::string& type, const std::string& data) const {
-+ dispatchEvent("onPaste", [type, data](jsi::Runtime& runtime) {
-+ auto payload = jsi::Object(runtime);
-+ auto items = jsi::Array(runtime, 1);
-+ auto item = jsi::Object(runtime);
-+ item.setProperty(runtime, "type", type);
-+ item.setProperty(runtime, "data", data);
-+ items.setValueAtIndex(runtime, 0, item);
-+ payload.setProperty(runtime, "items", items);
-+ return payload;
-+ });
-+}
-+
- void TextInputEventEmitter::dispatchTextInputEvent(
- const std::string& name,
- const TextInputMetrics& textInputMetrics,
-diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.h b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.h
-index bc5e624..07ccabc 100644
---- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.h
-+++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/react/renderer/components/iostextinput/TextInputEventEmitter.h
-@@ -48,6 +48,7 @@ class TextInputEventEmitter : public ViewEventEmitter {
- void onKeyPress(const KeyPressMetrics& keyPressMetrics) const;
- void onKeyPressSync(const KeyPressMetrics& keyPressMetrics) const;
- void onScroll(const TextInputMetrics& textInputMetrics) const;
-+ void onPaste(const std::string& type, const std::string& data) const;
-
- private:
- void dispatchTextInputEvent(
diff --git a/scripts/pod-install.sh b/scripts/pod-install.sh
new file mode 100755
index 000000000000..cb2976d64587
--- /dev/null
+++ b/scripts/pod-install.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+# This script ensures pod installs respect Podfile.lock as the source of truth.
+# Specifically, the podspecs for pods listed under the 'EXTERNAL SOURCES' key in the Podfile.lock are cached in the `ios/Pods/Local Podspecs` directory.
+# While caching results in significantly faster installs, if a cached podspec doesn't match the version in Podfile.lock, pod install will fail.
+# To prevent this, this script will find and delete any mismatched cached podspecs before running pod install
+
+# Exit immediately if any command exits with a non-zero status
+set -e
+
+# Go to project root
+START_DIR="$(pwd)"
+ROOT_DIR="$(dirname "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)")"
+cd "$ROOT_DIR" || exit 1
+
+# Cleanup and exit
+# param - status code
+function cleanupAndExit {
+ cd "$START_DIR" || exit 1
+ exit "$1"
+}
+
+source scripts/shellUtils.sh
+
+# Check if bundle is installed
+if ! bundle --version > /dev/null 2>&1; then
+ error 'bundle is not installed. Please install bundle and try again'
+ cleanupAndExit 1
+fi
+
+# Check if jq is installed
+if ! jq --version > /dev/null 2>&1; then
+ error 'jq is not installed. Please install jq and try again'
+ cleanupAndExit 1
+fi
+
+# Check if yq is installed
+if ! yq --version > /dev/null 2>&1; then
+ error 'yq is not installed. Please install yq and try again'
+ cleanupAndExit 1
+fi
+
+CACHED_PODSPEC_DIR='ios/Pods/Local Podspecs'
+if [ -d "$CACHED_PODSPEC_DIR" ]; then
+ info "Verifying pods from Podfile.lock match local podspecs..."
+
+ # Convert podfile.lock to json since yq is missing some features of jq (namely, if/else)
+ PODFILE_LOCK_AS_JSON="$(yq -o=json ios/Podfile.lock)"
+
+ # Retrieve a list of pods and their versions from Podfile.lock
+ declare PODS_FROM_LOCKFILE
+ if ! read_lines_into_array PODS_FROM_LOCKFILE < <(jq -r '.PODS | map (if (.|type) == "object" then keys[0] else . end) | .[]' < <(echo "$PODFILE_LOCK_AS_JSON")); then
+ error "Error: Could not parse pod versions from Podfile.lock"
+ cleanupAndExit 1
+ fi
+
+ for CACHED_PODSPEC_PATH in "$CACHED_PODSPEC_DIR"/*; do
+ if [ -f "$CACHED_PODSPEC_PATH" ]; then
+ # The next two lines use bash parameter expansion to get just the pod name from the path
+ # i.e: `ios/Pods/Local Podspecs/hermes-engine.podspec.json` to just `hermes-engine`
+ # It extracts the part of the string between the last `/` and the first `.`
+ CACHED_POD_NAME="${CACHED_PODSPEC_PATH##*/}"
+ CACHED_POD_NAME="${CACHED_POD_NAME%%.*}"
+
+ info "🫛 Verifying local pod $CACHED_POD_NAME"
+ CACHED_POD_VERSION="$(jq -r '.version' < <(cat "$CACHED_PODSPEC_PATH"))"
+ for POD_FROM_LOCKFILE in "${PODS_FROM_LOCKFILE[@]}"; do
+ # Extract the pod name and version that was parsed from the lockfile. POD_FROM_LOCKFILE looks like `PodName (version)`
+ IFS=' ' read -r POD_NAME_FROM_LOCKFILE POD_VERSION_FROM_LOCKFILE <<< "$POD_FROM_LOCKFILE"
+ if [[ "$CACHED_POD_NAME" == "$POD_NAME_FROM_LOCKFILE" ]]; then
+ if [[ "$POD_VERSION_FROM_LOCKFILE" != "($CACHED_POD_VERSION)" ]]; then
+ clear_last_line
+ info "⚠️ found mismatched pod: $CACHED_POD_NAME, removing local podspec $CACHED_PODSPEC_PATH"
+ rm "$CACHED_PODSPEC_PATH"
+ echo -e "\n"
+ fi
+ break
+ fi
+ done
+ clear_last_line
+ fi
+ done
+fi
+
+cd ios || cleanupAndExit 1
+bundle exec pod install
+
+# Go back to where we started
+cleanupAndExit 0
diff --git a/scripts/shellUtils.sh b/scripts/shellUtils.sh
index fa44f2ee7d3a..c1ceace09d0a 100644
--- a/scripts/shellUtils.sh
+++ b/scripts/shellUtils.sh
@@ -41,6 +41,11 @@ function title {
printf "\n%s%s%s\n" "$TITLE" "$1" "$RESET"
}
+# Function to clear the last printed line
+clear_last_line() {
+ echo -ne "\033[1A\033[K"
+}
+
function assert_equal {
if [[ "$1" != "$2" ]]; then
error "Assertion failed: $1 is not equal to $2"
diff --git a/src/CONST.ts b/src/CONST.ts
index b2748765f54d..bfafa031dd10 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -970,6 +970,8 @@ const CONST = {
HOMEPAGE_INITIAL_RENDER: 'homepage_initial_render',
REPORT_INITIAL_RENDER: 'report_initial_render',
SWITCH_REPORT: 'switch_report',
+ SWITCH_REPORT_FROM_PREVIEW: 'switch_report_from_preview',
+ SWITCH_REPORT_THREAD: 'switch_report_thread',
SIDEBAR_LOADED: 'sidebar_loaded',
LOAD_SEARCH_OPTIONS: 'load_search_options',
COLD: 'cold',
diff --git a/src/components/AttachmentPicker/index.native.tsx b/src/components/AttachmentPicker/index.native.tsx
index 0a14d18a2324..edcdabed9101 100644
--- a/src/components/AttachmentPicker/index.native.tsx
+++ b/src/components/AttachmentPicker/index.native.tsx
@@ -174,8 +174,10 @@ function AttachmentPicker({type = CONST.ATTACHMENT_PICKER_TYPE.FILE, children, s
if (isHEIC && targetAssetUri) {
manipulateAsync(targetAssetUri, [], {format: SaveFormat.JPEG})
.then((manipResult) => {
+ const uri = manipResult.uri;
const convertedAsset = {
- uri: manipResult.uri,
+ uri,
+ name: uri.substring(uri.lastIndexOf('/') + 1).split('?')[0],
type: 'image/jpeg',
width: manipResult.width,
height: manipResult.height,
diff --git a/src/components/Composer/index.native.tsx b/src/components/Composer/index.native.tsx
index c932c5d798f7..68a8c56c4df9 100644
--- a/src/components/Composer/index.native.tsx
+++ b/src/components/Composer/index.native.tsx
@@ -1,9 +1,8 @@
import type {MarkdownStyle} from '@expensify/react-native-live-markdown';
import type {ForwardedRef} from 'react';
import React, {useCallback, useMemo, useRef} from 'react';
-import type {NativeSyntheticEvent, TextInput, TextInputChangeEventData, TextInputPasteEventData} from 'react-native';
+import type {NativeSyntheticEvent, TextInput, TextInputChangeEventData} from 'react-native';
import {StyleSheet} from 'react-native';
-import type {FileObject} from '@components/AttachmentModal';
import type {AnimatedMarkdownTextInputRef} from '@components/RNMarkdownTextInput';
import RNMarkdownTextInput from '@components/RNMarkdownTextInput';
import useMarkdownStyle from '@hooks/useMarkdownStyle';
@@ -21,7 +20,6 @@ const excludeReportMentionStyle: Array = ['mentionReport'];
function Composer(
{
onClear: onClearProp = () => {},
- onPasteFile = () => {},
isDisabled = false,
maxLines,
isComposerFullSize = false,
@@ -71,19 +69,6 @@ function Composer(
},
[onClearProp],
);
- const pasteFile = useCallback(
- (e: NativeSyntheticEvent) => {
- const clipboardContent = e.nativeEvent.items[0];
- if (clipboardContent.type === 'text/plain') {
- return;
- }
- const fileURI = clipboardContent.data;
- const fileName = fileURI.split('/').pop();
- const file: FileObject = {uri: fileURI, name: fileName, type: clipboardContent.type};
- onPasteFile(file);
- },
- [onPasteFile],
- );
const maxHeightStyle = useMemo(() => StyleUtils.getComposerMaxHeightStyle(maxLines, isComposerFullSize), [StyleUtils, isComposerFullSize, maxLines]);
const composerStyle = useMemo(() => StyleSheet.flatten([style, textContainsOnlyEmojis ? styles.onlyEmojisTextLineHeight : {}]), [style, textContainsOnlyEmojis, styles]);
@@ -105,7 +90,6 @@ function Composer(
/* eslint-disable-next-line react/jsx-props-no-spreading */
{...props}
readOnly={isDisabled}
- onPaste={pasteFile}
onBlur={(e) => {
if (!isFocused) {
// eslint-disable-next-line react-compiler/react-compiler
diff --git a/src/components/Composer/types.ts b/src/components/Composer/types.ts
index 8287e2de3f2d..e6d8a882f3b8 100644
--- a/src/components/Composer/types.ts
+++ b/src/components/Composer/types.ts
@@ -1,5 +1,4 @@
import type {NativeSyntheticEvent, StyleProp, TextInputProps, TextInputSelectionChangeEventData, TextStyle} from 'react-native';
-import type {FileObject} from '@components/AttachmentModal';
type TextSelection = {
start: number;
@@ -38,7 +37,7 @@ type ComposerProps = Omit & {
onChangeText?: (numberOfLines: string) => void;
/** Callback method to handle pasting a file */
- onPasteFile?: (file: FileObject) => void;
+ onPasteFile?: (file: File) => void;
/** General styles to apply to the text input */
// eslint-disable-next-line react/forbid-prop-types
diff --git a/src/components/ConnectToNetSuiteButton/index.tsx b/src/components/ConnectToNetSuiteButton/index.tsx
index 928bc01f12c1..24c19689da23 100644
--- a/src/components/ConnectToNetSuiteButton/index.tsx
+++ b/src/components/ConnectToNetSuiteButton/index.tsx
@@ -1,12 +1,12 @@
import React, {useRef, useState} from 'react';
import type {View} from 'react-native';
-import {useOnyx} from 'react-native-onyx';
import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal';
import Button from '@components/Button';
import * as Expensicons from '@components/Icon/Expensicons';
import PopoverMenu from '@components/PopoverMenu';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {removePolicyConnection} from '@libs/actions/connections';
@@ -15,7 +15,6 @@ import Navigation from '@libs/Navigation/Navigation';
import {isControlPolicy} from '@libs/PolicyUtils';
import type {AnchorPosition} from '@styles/index';
import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {ConnectToNetSuiteButtonProps} from './types';
@@ -23,7 +22,7 @@ function ConnectToNetSuiteButton({policyID, shouldDisconnectIntegrationBeforeCon
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isOffline} = useNetwork();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false);
diff --git a/src/components/ConnectToSageIntacctButton/index.tsx b/src/components/ConnectToSageIntacctButton/index.tsx
index 6c6523ad6e75..fa6b26216c4c 100644
--- a/src/components/ConnectToSageIntacctButton/index.tsx
+++ b/src/components/ConnectToSageIntacctButton/index.tsx
@@ -1,12 +1,12 @@
import React, {useRef, useState} from 'react';
import type {View} from 'react-native';
-import {useOnyx} from 'react-native-onyx';
import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal';
import Button from '@components/Button';
import * as Expensicons from '@components/Icon/Expensicons';
import PopoverMenu from '@components/PopoverMenu';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {removePolicyConnection} from '@libs/actions/connections';
@@ -15,7 +15,6 @@ import Navigation from '@libs/Navigation/Navigation';
import {isControlPolicy} from '@libs/PolicyUtils';
import type {AnchorPosition} from '@styles/index';
import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {PolicyConnectionName} from '@src/types/onyx/Policy';
@@ -30,7 +29,7 @@ function ConnectToSageIntacctButton({policyID, shouldDisconnectIntegrationBefore
const {translate} = useLocalize();
const {isOffline} = useNetwork();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false);
diff --git a/src/components/EmptyStateComponent/index.tsx b/src/components/EmptyStateComponent/index.tsx
index 1efa526355f1..178267de8429 100644
--- a/src/components/EmptyStateComponent/index.tsx
+++ b/src/components/EmptyStateComponent/index.tsx
@@ -23,7 +23,6 @@ function EmptyStateComponent({
subtitle,
headerStyles,
headerContentStyles,
- emptyStateForegroundStyles,
minModalHeight = 400,
}: EmptyStateComponentProps) {
const styles = useThemeStyles();
@@ -85,8 +84,7 @@ function EmptyStateComponent({
shouldAnimate={false}
/>
-
-
+
{HeaderComponent}
diff --git a/src/components/EmptyStateComponent/types.ts b/src/components/EmptyStateComponent/types.ts
index 94860893c2c4..80fac980864f 100644
--- a/src/components/EmptyStateComponent/types.ts
+++ b/src/components/EmptyStateComponent/types.ts
@@ -19,7 +19,6 @@ type SharedProps = {
headerStyles?: StyleProp;
headerMediaType: T;
headerContentStyles?: StyleProp;
- emptyStateForegroundStyles?: StyleProp;
minModalHeight?: number;
};
diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx
index b518acb069f3..5f7bcd7753c8 100644
--- a/src/components/FeatureTrainingModal.tsx
+++ b/src/components/FeatureTrainingModal.tsx
@@ -204,7 +204,7 @@ function FeatureTrainingModal({
{renderIllustration()}
- {title && description && (
+ {!!title && !!description && (
{title}
{description}
@@ -220,7 +220,7 @@ function FeatureTrainingModal({
onInputChange={toggleWillShowAgain}
/>
)}
- {helpText && (
+ {!!helpText && (
{reportItem.transactions.map((transaction) => (
(null);
const {updateVolume} = useVolumeContext();
const {videoPopoverMenuPlayerRef, currentPlaybackSpeed, setCurrentPlaybackSpeed} = useVideoPopoverMenuContext();
+ const {source} = videoPopoverMenuPlayerRef.current?.props ?? {};
+ const shouldUseNewRate = typeof source === 'number' || !source || source.uri !== sourceURL;
const togglePlayCurrentVideo = useCallback(() => {
videoResumeTryNumberRef.current = 0;
@@ -149,8 +151,10 @@ function BaseVideoPlayer({
if (!('rate' in status && status.rate)) {
return;
}
+ if (shouldUseNewRate) {
+ setCurrentPlaybackSpeed(status.rate as PlaybackSpeed);
+ }
setIsPopoverVisible(true);
- setCurrentPlaybackSpeed(status.rate as PlaybackSpeed);
});
if (!event || !('nativeEvent' in event)) {
return;
@@ -177,6 +181,9 @@ function BaseVideoPlayer({
[playVideo, videoResumeTryNumberRef],
);
+ const prevIsMutedRef = useRef(false);
+ const prevVolumeRef = useRef(0);
+
const handlePlaybackStatusUpdate = useCallback(
(status: AVPlaybackStatus) => {
if (!status.isLoaded) {
@@ -189,6 +196,16 @@ function BaseVideoPlayer({
onPlaybackStatusUpdate?.(status);
return;
}
+
+ if (prevIsMutedRef.current && prevVolumeRef.current === 0 && !status.isMuted) {
+ updateVolume(0.25);
+ }
+ if (isFullScreenRef.current && prevVolumeRef.current !== 0 && status.volume === 0 && !status.isMuted) {
+ currentVideoPlayerRef.current?.setStatusAsync({isMuted: true});
+ }
+ prevIsMutedRef.current = status.isMuted;
+ prevVolumeRef.current = status.volume;
+
const isVideoPlaying = status.isPlaying;
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const currentDuration = status.durationMillis || videoDuration * 1000;
@@ -339,12 +356,15 @@ function BaseVideoPlayer({
updateCurrentlyPlayingURL(url);
}, [shouldPlay, updateCurrentlyPlayingURL, url]);
+ useEffect(() => {
+ videoPlayerRef.current?.setStatusAsync({volume: 0});
+ }, []);
+
return (
<>
{/* We need to wrap the video component in a component that will catch unhandled pointer events. Otherwise, these
events will bubble up the tree, and it will cause unexpected press behavior. */}
@@ -410,8 +430,7 @@ function BaseVideoPlayer({
playVideo();
}
onVideoLoaded?.(e);
- const {source} = videoPopoverMenuPlayerRef.current?.props ?? {};
- if (typeof source === 'number' || !source || source.uri !== sourceURL) {
+ if (shouldUseNewRate) {
return;
}
videoPlayerRef.current?.setStatusAsync?.({rate: currentPlaybackSpeed});
diff --git a/src/components/VideoPlayerContexts/PlaybackContext.tsx b/src/components/VideoPlayerContexts/PlaybackContext.tsx
index 60594c25feb9..48f60392b4b5 100644
--- a/src/components/VideoPlayerContexts/PlaybackContext.tsx
+++ b/src/components/VideoPlayerContexts/PlaybackContext.tsx
@@ -1,8 +1,9 @@
-import type {AVPlaybackStatusToSet} from 'expo-av';
+import type {AVPlaybackStatus, AVPlaybackStatusToSet} from 'expo-av';
import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import type {View} from 'react-native';
import type {VideoWithOnFullScreenUpdate} from '@components/VideoPlayer/types';
import useCurrentReportID from '@hooks/useCurrentReportID';
+import usePrevious from '@hooks/usePrevious';
import type ChildrenProps from '@src/types/utils/ChildrenProps';
import type {PlaybackContext, StatusCallback} from './types';
@@ -15,7 +16,9 @@ function PlaybackContextProvider({children}: ChildrenProps) {
const [originalParent, setOriginalParent] = useState(null);
const currentVideoPlayerRef = useRef(null);
const {currentReportID} = useCurrentReportID() ?? {};
+ const prevCurrentReportID = usePrevious(currentReportID);
const videoResumeTryNumberRef = useRef(0);
+ const playVideoPromiseRef = useRef>();
const pauseVideo = useCallback(() => {
currentVideoPlayerRef.current?.setStatusAsync?.({shouldPlay: false});
@@ -31,7 +34,7 @@ function PlaybackContextProvider({children}: ChildrenProps) {
if ('durationMillis' in status && status.durationMillis === status.positionMillis) {
newStatus.positionMillis = 0;
}
- currentVideoPlayerRef.current?.setStatusAsync(newStatus);
+ playVideoPromiseRef.current = currentVideoPlayerRef.current?.setStatusAsync(newStatus);
});
}, [currentVideoPlayerRef]);
@@ -73,21 +76,29 @@ function PlaybackContextProvider({children}: ChildrenProps) {
);
const resetVideoPlayerData = useCallback(() => {
- videoResumeTryNumberRef.current = 0;
- stopVideo();
- setCurrentlyPlayingURL(null);
- setSharedElement(null);
- setOriginalParent(null);
- currentVideoPlayerRef.current = null;
- unloadVideo();
+ // Play video is an async operation and if we call stop video before the promise is completed,
+ // it will throw a console error. So, we'll wait until the promise is resolved before stopping the video.
+ (playVideoPromiseRef.current ?? Promise.resolve()).then(stopVideo).finally(() => {
+ videoResumeTryNumberRef.current = 0;
+ setCurrentlyPlayingURL(null);
+ setSharedElement(null);
+ setOriginalParent(null);
+ currentVideoPlayerRef.current = null;
+ unloadVideo();
+ });
}, [stopVideo, unloadVideo]);
useEffect(() => {
- if (!currentReportID) {
+ // This logic ensures that resetVideoPlayerData is only called when currentReportID
+ // changes from one valid value (i.e., not an empty string or '-1') to another valid value.
+ // This prevents the video that plays when the app opens from being interrupted when currentReportID
+ // is initially empty or '-1', or when it changes from empty/'-1' to another value
+ // after the report screen in the central pane is mounted on the large screen.
+ if (!currentReportID || !prevCurrentReportID || currentReportID === '-1' || prevCurrentReportID === '-1') {
return;
}
resetVideoPlayerData();
- }, [currentReportID, resetVideoPlayerData]);
+ }, [currentReportID, prevCurrentReportID, resetVideoPlayerData]);
const contextValue = useMemo(
() => ({
diff --git a/src/hooks/useEmptyViewHeaderHeight/const.ts b/src/hooks/useEmptyViewHeaderHeight/const.ts
new file mode 100644
index 000000000000..83327ad36c8b
--- /dev/null
+++ b/src/hooks/useEmptyViewHeaderHeight/const.ts
@@ -0,0 +1,5 @@
+const HEADER_HEIGHT = 80;
+const BUTTON_HEIGHT = 40;
+const BUTTON_MARGIN = 12;
+
+export {HEADER_HEIGHT, BUTTON_HEIGHT, BUTTON_MARGIN};
diff --git a/src/hooks/useEmptyViewHeaderHeight/index.ios.ts b/src/hooks/useEmptyViewHeaderHeight/index.ios.ts
new file mode 100644
index 000000000000..d59e105574bf
--- /dev/null
+++ b/src/hooks/useEmptyViewHeaderHeight/index.ios.ts
@@ -0,0 +1,10 @@
+import useSafeAreaInsets from '@hooks/useSafeAreaInsets';
+import {BUTTON_HEIGHT, BUTTON_MARGIN, HEADER_HEIGHT} from './const';
+
+function useEmptyViewHeaderHeight(isSmallScreenWidth: boolean): number {
+ const safeAreaInsets = useSafeAreaInsets();
+
+ return isSmallScreenWidth ? HEADER_HEIGHT + BUTTON_HEIGHT + BUTTON_MARGIN + safeAreaInsets.top : HEADER_HEIGHT;
+}
+
+export default useEmptyViewHeaderHeight;
diff --git a/src/hooks/useEmptyViewHeaderHeight/index.ts b/src/hooks/useEmptyViewHeaderHeight/index.ts
new file mode 100644
index 000000000000..d241d95b236f
--- /dev/null
+++ b/src/hooks/useEmptyViewHeaderHeight/index.ts
@@ -0,0 +1,7 @@
+import {BUTTON_HEIGHT, BUTTON_MARGIN, HEADER_HEIGHT} from './const';
+
+function useEmptyViewHeaderHeight(isSmallScreenWidth: boolean): number {
+ return isSmallScreenWidth ? HEADER_HEIGHT + BUTTON_HEIGHT + BUTTON_MARGIN : HEADER_HEIGHT;
+}
+
+export default useEmptyViewHeaderHeight;
diff --git a/src/hooks/usePolicy.ts b/src/hooks/usePolicy.ts
new file mode 100644
index 000000000000..f08b1b323022
--- /dev/null
+++ b/src/hooks/usePolicy.ts
@@ -0,0 +1,17 @@
+import {useOnyx} from 'react-native-onyx';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+function getPolicyIDOrDefault(policyID?: string) {
+ if (!policyID || policyID === CONST.POLICY.OWNER_EMAIL_FAKE) {
+ return '-1';
+ }
+ return policyID;
+}
+
+function usePolicy(policyID?: string) {
+ const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${getPolicyIDOrDefault(policyID)}`);
+ return policy;
+}
+
+export default usePolicy;
diff --git a/src/languages/en.ts b/src/languages/en.ts
index a139a5ca4d72..bfe0eef70178 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -625,7 +625,7 @@ export default {
},
allSettingsScreen: {
subscription: 'Subscription',
- cardsAndDomains: 'Cards & Domains',
+ domains: 'Domains',
},
tabSelector: {
chat: 'Chat',
@@ -3596,7 +3596,7 @@ export default {
descriptionOptional: 'Description (optional)',
shareSomewhere: 'Share somewhere',
pleaseEnterTaskName: 'Please enter a title',
- pleaseEnterTaskDestination: 'Please select with whom you want to share.',
+ pleaseEnterTaskDestination: 'Please select where you want to share this task.',
},
task: {
task: 'Task',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 30086da1fa89..76d55a096808 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -618,7 +618,7 @@ export default {
},
allSettingsScreen: {
subscription: 'Suscripcion',
- cardsAndDomains: 'Tarjetas y Dominios',
+ domains: 'Dominios',
},
tabSelector: {
chat: 'Chat',
@@ -3650,7 +3650,7 @@ export default {
descriptionOptional: 'Descripción (opcional)',
shareSomewhere: 'Compartir en algún lugar',
pleaseEnterTaskName: 'Por favor, introduce un título',
- pleaseEnterTaskDestination: 'Por favor, selecciona con quién deseas compartir.',
+ pleaseEnterTaskDestination: 'Por favor, selecciona dónde deseas compartir esta tarea.',
},
task: {
task: 'Tarea',
diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts
index 5f6d99332336..986fd165d2d7 100644
--- a/src/libs/IOUUtils.ts
+++ b/src/libs/IOUUtils.ts
@@ -141,7 +141,10 @@ function insertTagIntoTransactionTagsString(transactionTags: string, tag: string
const tagArray = TransactionUtils.getTagArrayFromName(transactionTags);
tagArray[tagIndex] = tag;
- return tagArray.join(CONST.COLON).replace(/:*$/, '');
+ return tagArray
+ .map((tagItem) => tagItem.trim())
+ .filter((tagItem) => !!tagItem)
+ .join(CONST.COLON);
}
function isMovingTransactionFromTrackExpense(action?: IOUAction) {
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
index 64816562a507..071b6d8270d7 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
@@ -1,7 +1,7 @@
import React, {memo, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
-import Onyx, {useOnyx} from 'react-native-onyx';
+import Onyx, {withOnyx} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import OptionsListContextProvider from '@components/OptionListContextProvider';
import useActiveWorkspace from '@hooks/useActiveWorkspace';
@@ -44,6 +44,7 @@ import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
+import type * as OnyxTypes from '@src/types/onyx';
import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
import CENTRAL_PANE_SCREENS from './CENTRAL_PANE_SCREENS';
@@ -59,6 +60,17 @@ import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator';
import RightModalNavigator from './Navigators/RightModalNavigator';
import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator';
+type AuthScreensProps = {
+ /** Session of currently logged in user */
+ session: OnyxEntry;
+
+ /** The report ID of the last opened public room as anonymous user */
+ lastOpenedPublicRoomID: OnyxEntry;
+
+ /** The last Onyx update ID was applied to the client */
+ initialLastUpdateIDAppliedToClient: OnyxEntry;
+};
+
const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default;
const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default;
const loadLogOutPreviousUserPage = () => require('../../../pages/LogOutPreviousUserPage').default;
@@ -190,14 +202,11 @@ const modalScreenListenersWithCancelSearch = {
},
};
-function AuthScreens() {
+function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDAppliedToClient}: AuthScreensProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isSmallScreenWidth} = useWindowDimensions();
const {isMediumOrLargerScreenWidth} = useOnboardingLayout();
- const [session] = useOnyx(ONYXKEYS.SESSION);
- const [lastOpenedPublicRoomID] = useOnyx(ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID);
- const [initialLastUpdateIDAppliedToClient] = useOnyx(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT);
const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils);
const {canUseDefaultRooms} = usePermissions();
const {activeWorkspaceID} = useActiveWorkspace();
@@ -513,4 +522,14 @@ AuthScreens.displayName = 'AuthScreens';
const AuthScreensMemoized = memo(AuthScreens, () => true);
-export default AuthScreensMemoized;
+export default withOnyx({
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ lastOpenedPublicRoomID: {
+ key: ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID,
+ },
+ initialLastUpdateIDAppliedToClient: {
+ key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT,
+ },
+})(AuthScreensMemoized);
diff --git a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx
index 64f827f3ddba..bd60b0a873d9 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx
@@ -8,6 +8,7 @@ import useDisableModalDismissOnEscape from '@hooks/useDisableModalDismissOnEscap
import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useOnboardingLayout from '@hooks/useOnboardingLayout';
import useThemeStyles from '@hooks/useThemeStyles';
+import useWindowDimensions from '@hooks/useWindowDimensions';
import hasCompletedGuidedSetupFlowSelector from '@libs/hasCompletedGuidedSetupFlowSelector';
import OnboardingModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/OnboardingModalNavigatorScreenOptions';
import Navigation from '@libs/Navigation/Navigation';
@@ -19,6 +20,7 @@ import OnboardingWork from '@pages/OnboardingWork';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import Overlay from './Overlay';
@@ -30,6 +32,7 @@ function OnboardingModalNavigator() {
const [hasCompletedGuidedSetupFlow] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
selector: hasCompletedGuidedSetupFlowSelector,
});
+ const {isSmallScreenWidth} = useWindowDimensions();
useDisableModalDismissOnEscape();
@@ -38,12 +41,18 @@ function OnboardingModalNavigator() {
return;
}
Navigation.isNavigationReady().then(() => {
- // Need to go back to previous route and then redirect to Concierge,
+ // On small screens, pop all navigation states and go back to HOME.
+ // On large screens, need to go back to previous route and then redirect to Concierge,
// otherwise going back on Concierge will go to onboarding and then redirected to Concierge again
- Navigation.goBack();
- Report.navigateToConciergeChat();
+ if (isSmallScreenWidth) {
+ Navigation.setShouldPopAllStateOnUP(true);
+ Navigation.goBack(ROUTES.HOME, true, true);
+ } else {
+ Navigation.goBack();
+ Report.navigateToConciergeChat();
+ }
});
- }, [hasCompletedGuidedSetupFlow]);
+ }, [hasCompletedGuidedSetupFlow, isSmallScreenWidth]);
const outerViewRef = React.useRef(null);
diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
index 95d6446aaf1e..f06757793d8b 100644
--- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
@@ -1,5 +1,5 @@
import {useNavigation} from '@react-navigation/native';
-import React, {memo, useCallback, useEffect} from 'react';
+import React, {memo, useCallback, useEffect, useState} from 'react';
import {NativeModules, View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Icon from '@components/Icon';
@@ -18,6 +18,7 @@ import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
import type {RootStackParamList, State} from '@libs/Navigation/types';
import {isCentralPaneName} from '@libs/NavigationUtils';
import {getCurrentSearchParams} from '@libs/SearchUtils';
+import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
import BottomTabAvatar from '@pages/home/sidebar/BottomTabAvatar';
import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton';
@@ -41,6 +42,12 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) {
const navigation = useNavigation();
const {activeWorkspaceID} = useActiveWorkspace();
const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
+ const transactionViolations = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
+ const [chatTabBrickRoad, setChatTabBrickRoad] = useState(getChatTabBrickRoad(activeWorkspaceID));
+
+ useEffect(() => {
+ setChatTabBrickRoad(getChatTabBrickRoad(activeWorkspaceID));
+ }, [activeWorkspaceID, transactionViolations]);
useEffect(() => {
const navigationState = navigation.getState() as State | undefined;
@@ -67,7 +74,6 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) {
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [isLoadingApp]);
- const chatTabBrickRoad = getChatTabBrickRoad(activeWorkspaceID);
const navigateToChats = useCallback(() => {
if (selectedTab === SCREENS.HOME) {
return;
diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx
index 0f4c41b9cbfc..dc3ab4c48c08 100644
--- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx
@@ -8,6 +8,7 @@ import {PressableWithoutFeedback} from '@components/Pressable';
import Tooltip from '@components/Tooltip';
import WorkspaceSwitcherButton from '@components/WorkspaceSwitcherButton';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
@@ -25,7 +26,7 @@ function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true}
const styles = useThemeStyles();
const theme = useTheme();
const {translate} = useLocalize();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID}`);
+ const policy = usePolicy(activeWorkspaceID);
const [session] = useOnyx(ONYXKEYS.SESSION, {selector: (sessionValue) => sessionValue && {authTokenType: sessionValue.authTokenType}});
const isAnonymousUser = Session.isAnonymousUser(session);
diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts
index 6572b1887614..544bc228fa70 100644
--- a/src/libs/NextStepUtils.ts
+++ b/src/libs/NextStepUtils.ts
@@ -10,6 +10,7 @@ import type {Message} from '@src/types/onyx/ReportNextStep';
import type DeepValueOf from '@src/types/utils/DeepValueOf';
import DateUtils from './DateUtils';
import EmailUtils from './EmailUtils';
+import * as PersonalDetailsUtils from './PersonalDetailsUtils';
import * as PolicyUtils from './PolicyUtils';
import * as ReportUtils from './ReportUtils';
@@ -59,6 +60,20 @@ function parseMessage(messages: Message[] | undefined) {
return `${formattedHtml}`;
}
+function getNextApproverDisplayName(policy: Policy, ownerAccountID: number, submitToAccountID: number, report: OnyxEntry) {
+ const approvalChain = ReportUtils.getApprovalChain(policy, ownerAccountID, report?.total ?? 0);
+ if (approvalChain.length === 0) {
+ return ReportUtils.getDisplayNameForParticipant(submitToAccountID);
+ }
+
+ const nextApproverEmail = approvalChain.length === 1 ? approvalChain[0] : approvalChain[approvalChain.indexOf(currentUserEmail) + 1];
+ if (!nextApproverEmail) {
+ return ReportUtils.getDisplayNameForParticipant(submitToAccountID);
+ }
+
+ return PersonalDetailsUtils.getPersonalDetailByEmail(nextApproverEmail)?.displayName ?? nextApproverEmail;
+}
+
/**
* Generates an optimistic nextStep based on a current report status and other properties.
*
@@ -78,7 +93,8 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf, predictedNextStatus: ValueOf(sortedItems: TResource[], pages:
const result = [sortedPages[0]];
for (let i = 1; i < sortedPages.length; i++) {
const page = sortedPages[i];
- const prevPage = sortedPages[i - 1];
+ const prevPage = result[result.length - 1];
// Current page is inside the previous page, skip
if (page.lastIndex <= prevPage.lastIndex && page.lastID !== CONST.PAGINATION_END_ID) {
diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts
index 1eef60c24245..7468fb9a3679 100644
--- a/src/libs/PolicyUtils.ts
+++ b/src/libs/PolicyUtils.ts
@@ -292,7 +292,7 @@ function getTagList(policyTagList: OnyxEntry, tagIndex: number):
* Cleans up escaping of colons (used to create multi-level tags, e.g. "Parent: Child") in the tag name we receive from the backend
*/
function getCleanedTagName(tag: string) {
- return tag?.replace(/\\{1,2}:/g, CONST.COLON);
+ return tag?.replace(/\\:/g, CONST.COLON);
}
/**
@@ -461,6 +461,32 @@ function getSubmitToAccountID(policy: OnyxEntry, employeeAccountID: numb
return getAccountIDsByLogins([employee.submitsTo ?? defaultApprover])[0];
}
+function getSubmitToEmail(policy: OnyxEntry, employeeAccountID: number): string {
+ const submitToAccountID = getSubmitToAccountID(policy, employeeAccountID);
+ return getLoginsByAccountIDs([submitToAccountID])[0] ?? '';
+}
+
+/**
+ * Returns the email of the account to forward the report to depending on the approver's approval limit.
+ * Used for advanced approval mode only.
+ */
+function getForwardsToAccount(policy: OnyxEntry, employeeEmail: string, reportTotal: number): string {
+ if (!isControlOnAdvancedApprovalMode(policy)) {
+ return '';
+ }
+
+ const employee = policy?.employeeList?.[employeeEmail];
+ if (!employee) {
+ return '';
+ }
+
+ const positiveReportTotal = Math.abs(reportTotal);
+ if (employee.approvalLimit && employee.overLimitForwardsTo && positiveReportTotal > employee.approvalLimit) {
+ return employee.overLimitForwardsTo;
+ }
+ return employee.forwardsTo ?? '';
+}
+
/**
* Returns the accountID of the policy reimburser, if not available — falls back to the policy owner.
*/
@@ -916,7 +942,6 @@ export {
getPolicyBrickRoadIndicatorStatus,
getPolicyEmployeeListByIdWithoutCurrentUser,
getSortedTagKeys,
- getSubmitToAccountID,
getTagList,
getTagListName,
getTagLists,
@@ -984,6 +1009,8 @@ export {
getIntegrationLastSuccessfulDate,
getCurrentConnectionName,
getCustomersOrJobsLabelNetSuite,
+ getDefaultApprover,
+ getApprovalWorkflow,
getReimburserAccountID,
isControlPolicy,
isNetSuiteCustomSegmentRecord,
@@ -994,6 +1021,9 @@ export {
getCurrentTaxID,
areSettingsInErrorFields,
settingsPendingAction,
+ getSubmitToEmail,
+ getForwardsToAccount,
+ getSubmitToAccountID,
};
export type {MemberEmailsToAccountIDs};
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 157baba2775a..62e259b8f05c 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -157,6 +157,7 @@ type OptimisticExpenseReport = Pick<
| 'parentReportID'
| 'lastVisibleActionCreated'
| 'parentReportActionID'
+ | 'fieldList'
>;
type OptimisticIOUReportAction = Pick<
@@ -391,6 +392,7 @@ type OptimisticIOUReport = Pick<
| 'notificationPreference'
| 'parentReportID'
| 'lastVisibleActionCreated'
+ | 'fieldList'
>;
type DisplayNameWithTooltips = Array>;
@@ -2848,6 +2850,11 @@ function canEditMoneyRequest(reportAction: OnyxInputOrEntry
return false;
}
- if ((fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT || fieldToEdit === CONST.EDIT_REQUEST_FIELD.CURRENCY) && TransactionUtils.isDistanceRequest(transaction)) {
- const policy = getPolicy(moneyRequestReport?.reportID ?? '-1');
- const isAdmin = isExpenseReport(moneyRequestReport) && policy?.role === CONST.POLICY.ROLE.ADMIN;
- const isManager = isExpenseReport(moneyRequestReport) && currentUserAccountID === moneyRequestReport?.managerID;
+ const policy = getPolicy(moneyRequestReport?.reportID ?? '-1');
+ const isAdmin = isExpenseReport(moneyRequestReport) && policy?.role === CONST.POLICY.ROLE.ADMIN;
+ const isManager = isExpenseReport(moneyRequestReport) && currentUserAccountID === moneyRequestReport?.managerID;
+ if ((fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT || fieldToEdit === CONST.EDIT_REQUEST_FIELD.CURRENCY) && TransactionUtils.isDistanceRequest(transaction)) {
return isAdmin || isManager;
}
if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.RECEIPT) {
const isRequestor = currentUserAccountID === reportAction?.actorAccountID;
- return !isInvoiceReport(moneyRequestReport) && !TransactionUtils.isReceiptBeingScanned(transaction) && !TransactionUtils.isDistanceRequest(transaction) && isRequestor;
+ return (
+ !isInvoiceReport(moneyRequestReport) &&
+ !TransactionUtils.isReceiptBeingScanned(transaction) &&
+ !TransactionUtils.isDistanceRequest(transaction) &&
+ (isAdmin || isManager || isRequestor)
+ );
}
if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DISTANCE_RATE) {
@@ -2953,27 +2965,30 @@ function canHoldUnholdReportAction(reportAction: OnyxInputOrEntry)
const transactionID = moneyRequestReport ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID : 0;
const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction);
- const parentReport = getReportOrDraftReport(String(moneyRequestReport.parentReportID));
const parentReportAction = ReportActionsUtils.getParentReportAction(moneyRequestReport);
- const isRequestIOU = parentReport?.type === 'iou';
- const isRequestHoldCreator = isHoldCreator(transaction, moneyRequestReport?.reportID) && isRequestIOU;
+ const isRequestIOU = isIOUReport(moneyRequestReport);
+ const isHoldActionCreator = isHoldCreator(transaction, reportAction.childReportID ?? '-1');
+
const isTrackExpenseMoneyReport = isTrackExpenseReport(moneyRequestReport);
const isActionOwner =
typeof parentReportAction?.actorAccountID === 'number' &&
typeof currentUserPersonalDetails?.accountID === 'number' &&
parentReportAction.actorAccountID === currentUserPersonalDetails?.accountID;
const isApprover = isMoneyRequestReport(moneyRequestReport) && moneyRequestReport?.managerID !== null && currentUserPersonalDetails?.accountID === moneyRequestReport?.managerID;
+ const isAdmin = isPolicyAdmin(moneyRequestReport.policyID ?? '-1', allPolicies);
const isOnHold = TransactionUtils.isOnHold(transaction);
const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);
+ const isClosed = isClosedReport(moneyRequestReport);
- const canModifyStatus = !isTrackExpenseMoneyReport && (isPolicyAdmin || isActionOwner || isApprover);
+ const canModifyStatus = !isTrackExpenseMoneyReport && (isAdmin || isActionOwner || isApprover);
+ const canModifyUnholdStatus = !isTrackExpenseMoneyReport && (isAdmin || (isActionOwner && isHoldActionCreator) || isApprover);
const isDeletedParentAction = isEmptyObject(parentReportAction) || ReportActionsUtils.isDeletedAction(parentReportAction);
- const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentAction;
- const canHoldRequest = canHoldOrUnholdRequest && !isOnHold && (isRequestHoldCreator || (!isRequestIOU && canModifyStatus)) && !isScanning && !!transaction?.reimbursable;
+ const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentAction && !isClosed;
+ const canHoldRequest = canHoldOrUnholdRequest && !isOnHold && (isRequestIOU || canModifyStatus) && !isScanning && !!transaction?.reimbursable;
const canUnholdRequest =
- !!(canHoldOrUnholdRequest && isOnHold && !TransactionUtils.isDuplicate(transaction.transactionID, true) && (isRequestHoldCreator || (!isRequestIOU && canModifyStatus))) &&
+ !!(canHoldOrUnholdRequest && isOnHold && !TransactionUtils.isDuplicate(transaction.transactionID, true) && (isRequestIOU ? isHoldActionCreator : canModifyUnholdStatus)) &&
!!transaction?.reimbursable;
return {canHoldRequest, canUnholdRequest};
@@ -4082,6 +4097,8 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number
const formattedTotal = CurrencyUtils.convertToDisplayString(total, currency);
const personalDetails = getPersonalDetailsForAccountID(payerAccountID);
const payerEmail = 'login' in personalDetails ? personalDetails.login : '';
+ const policyID = getReport(chatReportID)?.policyID ?? '-1';
+ const policy = getPolicy(policyID);
const participants: Participants = {
[payeeAccountID]: {hidden: true},
@@ -4106,6 +4123,7 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number
notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN,
parentReportID: chatReportID,
lastVisibleActionCreated: DateUtils.getDBTime(),
+ fieldList: policy?.fieldList,
};
}
@@ -4224,6 +4242,8 @@ function buildOptimisticExpenseReport(
expenseReport.reportName = populateOptimisticReportFormula(titleReportField.defaultValue, expenseReport, policy);
}
+ expenseReport.fieldList = policy?.fieldList;
+
return expenseReport;
}
@@ -7492,6 +7512,23 @@ function isExported(reportActions: OnyxEntry) {
return Object.values(reportActions).some((action) => ReportActionsUtils.isExportIntegrationAction(action));
}
+function getApprovalChain(policy: OnyxEntry, employeeAccountID: number, reportTotal: number): string[] {
+ const approvalChain: string[] = [];
+
+ // If the policy is not on advanced approval mode, we should not use the approval chain even if it exists.
+ if (!PolicyUtils.isControlOnAdvancedApprovalMode(policy)) {
+ return approvalChain;
+ }
+
+ let nextApproverEmail = PolicyUtils.getSubmitToEmail(policy, employeeAccountID);
+
+ while (nextApproverEmail && !approvalChain.includes(nextApproverEmail)) {
+ approvalChain.push(nextApproverEmail);
+ nextApproverEmail = PolicyUtils.getForwardsToAccount(policy, nextApproverEmail, reportTotal);
+ }
+ return approvalChain;
+}
+
export {
addDomainToShortMention,
completeShortMention,
@@ -7787,6 +7824,7 @@ export {
getReport,
getReportNameValuePairs,
hasReportViolations,
+ getApprovalChain,
isIndividualInvoiceRoom,
};
diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts
index 9d2782acb792..35328dcf6421 100644
--- a/src/libs/SearchUtils.ts
+++ b/src/libs/SearchUtils.ts
@@ -285,8 +285,8 @@ function getSortedTransactionData(data: TransactionListItemType[], sortBy?: Sear
}
return data.sort((a, b) => {
- const aValue = sortingProperty === 'comment' ? a.comment.comment : a[sortingProperty];
- const bValue = sortingProperty === 'comment' ? b.comment.comment : b[sortingProperty];
+ const aValue = sortingProperty === 'comment' ? a.comment?.comment : a[sortingProperty];
+ const bValue = sortingProperty === 'comment' ? b.comment?.comment : b[sortingProperty];
if (aValue === undefined || bValue === undefined) {
return 0;
diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts
index 62d88e1fe706..473697708b14 100644
--- a/src/libs/SidebarUtils.ts
+++ b/src/libs/SidebarUtils.ts
@@ -407,7 +407,7 @@ function getOptionData({
? Localize.translate(preferredLocale, 'workspace.invite.invited')
: Localize.translate(preferredLocale, 'workspace.invite.removed');
const users = Localize.translate(preferredLocale, targetAccountIDsLength > 1 ? 'workspace.invite.users' : 'workspace.invite.user');
- result.alternateText = `${lastActorDisplayName} ${verb} ${targetAccountIDsLength} ${users}`.trim();
+ result.alternateText = ReportUtils.formatReportLastMessageText(`${lastActorDisplayName} ${verb} ${targetAccountIDsLength} ${users}`);
const roomName = lastActionOriginalMessage?.roomName ?? '';
if (roomName) {
@@ -415,18 +415,21 @@ function getOptionData({
lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM || lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM
? ` ${Localize.translate(preferredLocale, 'workspace.invite.to')}`
: ` ${Localize.translate(preferredLocale, 'workspace.invite.from')}`;
- result.alternateText += `${preposition} ${roomName}`;
+ result.alternateText += ReportUtils.formatReportLastMessageText(`${preposition} ${roomName}`);
}
} else if (ReportActionsUtils.isActionOfType(lastAction, CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.UPDATE_ROOM_DESCRIPTION)) {
result.alternateText = `${lastActorDisplayName} ${ReportActionsUtils.getUpdateRoomDescriptionMessage(lastAction)}`;
} else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.LEAVE_POLICY) {
result.alternateText = Localize.translateLocal('workspace.invite.leftWorkspace');
} else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && lastActorDisplayName && lastMessageTextFromReport) {
- result.alternateText = `${lastActorDisplayName}: ${lastMessageText}`;
+ result.alternateText = ReportUtils.formatReportLastMessageText(Parser.htmlToText(`${lastActorDisplayName}: ${lastMessageText}`));
} else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.ADD_TAG) {
result.alternateText = PolicyUtils.getCleanedTagName(ReportActionsUtils.getReportActionMessage(lastAction)?.text ?? '');
} else {
- result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : ReportActionsUtils.getLastVisibleMessage(report.reportID, {}, lastAction)?.lastMessageText;
+ result.alternateText =
+ lastMessageTextFromReport.length > 0
+ ? ReportUtils.formatReportLastMessageText(Parser.htmlToText(lastMessageText))
+ : ReportActionsUtils.getLastVisibleMessage(report.reportID, {}, lastAction)?.lastMessageText;
if (!result.alternateText) {
result.alternateText = ReportUtils.formatReportLastMessageText(getWelcomeMessage(report, policy).messageText ?? Localize.translateLocal('report.noActivityYet'));
}
@@ -435,11 +438,10 @@ function getOptionData({
if (!lastMessageText) {
lastMessageText = ReportUtils.formatReportLastMessageText(getWelcomeMessage(report, policy).messageText ?? Localize.translateLocal('report.noActivityYet'));
}
-
result.alternateText =
(ReportUtils.isGroupChat(report) || ReportUtils.isDeprecatedGroupDM(report)) && lastActorDisplayName
- ? `${lastActorDisplayName}: ${lastMessageText}`
- : lastMessageText || formattedLogin;
+ ? ReportUtils.formatReportLastMessageText(Parser.htmlToText(`${lastActorDisplayName}: ${lastMessageText}`))
+ : ReportUtils.formatReportLastMessageText(Parser.htmlToText(lastMessageText)) || formattedLogin;
}
result.isIOUReportOwner = ReportUtils.isIOUOwnedByCurrentUser(result as Report);
diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts
index c6d4602594d5..aceb053a75f7 100644
--- a/src/libs/TransactionUtils/index.ts
+++ b/src/libs/TransactionUtils/index.ts
@@ -163,7 +163,7 @@ function buildOptimisticTransaction(
created: created || DateUtils.getDBTime(),
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
receipt: receipt?.source ? {source: receipt.source, state: receipt.state ?? CONST.IOU.RECEIPT_STATE.SCANREADY} : {},
- filename: (receipt?.source ?? receipt?.name ?? filename).toString(),
+ filename: (receipt?.source ? receipt?.name ?? filename : filename).toString(),
category,
tag,
taxCode,
@@ -949,7 +949,7 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia
// Helper function to check if all comments exist
function doAllCommentsExist(items: Array>, firstTransaction: OnyxEntry) {
- return items.every((item) => !!item?.comment.comment === !!firstTransaction?.comment.comment);
+ return items.every((item) => !!item?.comment?.comment === !!firstTransaction?.comment?.comment);
}
// Helper function to check if all fields are equal for a given key
@@ -970,7 +970,7 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia
if (Object.prototype.hasOwnProperty.call(fieldsToCompare, fieldName)) {
const keys = fieldsToCompare[fieldName];
const firstTransaction = transactions[0];
- const isFirstTransactionCommentEmptyObject = typeof firstTransaction?.comment === 'object' && firstTransaction?.comment.comment === '';
+ const isFirstTransactionCommentEmptyObject = typeof firstTransaction?.comment === 'object' && firstTransaction?.comment?.comment === '';
if (fieldName === 'description') {
const allCommentsAreEqual = areAllCommentsEqual(transactions, firstTransaction);
@@ -978,7 +978,7 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia
const allCommentsAreEmpty = isFirstTransactionCommentEmptyObject && transactions.every((item) => item?.comment === undefined);
if (allCommentsAreEqual || allCommentsExist || allCommentsAreEmpty) {
- keep[fieldName] = firstTransaction?.comment.comment ?? firstTransaction?.comment;
+ keep[fieldName] = firstTransaction?.comment?.comment ?? firstTransaction?.comment;
} else {
processChanges(fieldName, transactions, keys);
}
diff --git a/src/libs/WorkspacesSettingsUtils.ts b/src/libs/WorkspacesSettingsUtils.ts
index d827a6cae000..bbe5cc777c30 100644
--- a/src/libs/WorkspacesSettingsUtils.ts
+++ b/src/libs/WorkspacesSettingsUtils.ts
@@ -4,12 +4,13 @@ import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
-import type {Policy, ReimbursementAccount, Report, ReportAction, ReportActions} from '@src/types/onyx';
+import type {Policy, ReimbursementAccount, Report, ReportAction, ReportActions, TransactionViolations} from '@src/types/onyx';
import type {Unit} from '@src/types/onyx/Policy';
import * as CurrencyUtils from './CurrencyUtils';
import type {Phrase, PhraseParameters} from './Localize';
import * as OptionsListUtils from './OptionsListUtils';
import {hasCustomUnitsError, hasEmployeeListError, hasPolicyError, hasTaxRateError} from './PolicyUtils';
+import * as ReportActionsUtils from './ReportActionsUtils';
import * as ReportConnection from './ReportConnection';
import * as ReportUtils from './ReportUtils';
@@ -46,6 +47,20 @@ Onyx.connect({
},
});
+let allTransactionViolations: NonNullable> = {};
+Onyx.connect({
+ key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
+ waitForCollectionCallback: true,
+ callback: (value) => {
+ if (!value) {
+ allTransactionViolations = {};
+ return;
+ }
+
+ allTransactionViolations = value;
+ },
+});
+
/**
* @param altReportActions Replaces (local) allReportActions used within (local) function getWorkspacesBrickRoads
* @returns BrickRoad for the policy passed as a param and optionally actionsByReport (if passed)
@@ -53,7 +68,23 @@ Onyx.connect({
const getBrickRoadForPolicy = (report: Report, altReportActions?: OnyxCollection): BrickRoad => {
const reportActions = (altReportActions ?? allReportActions)?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`] ?? {};
const reportErrors = OptionsListUtils.getAllReportErrors(report, reportActions);
- const doesReportContainErrors = Object.keys(reportErrors ?? {}).length !== 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined;
+ const oneTransactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(report.reportID, reportActions);
+ let doesReportContainErrors = Object.keys(reportErrors ?? {}).length !== 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined;
+
+ if (oneTransactionThreadReportID) {
+ const oneTransactionThreadReport = ReportUtils.getReport(oneTransactionThreadReportID);
+
+ if (
+ ReportUtils.shouldDisplayTransactionThreadViolations(
+ oneTransactionThreadReport,
+ allTransactionViolations,
+ reportActions[oneTransactionThreadReport?.parentReportActionID ?? '-1'],
+ )
+ ) {
+ doesReportContainErrors = CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
+ }
+ }
+
if (doesReportContainErrors) {
return CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
}
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index 9549bc23a9d8..ef5f6d6d61c0 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -2,7 +2,7 @@ import {format} from 'date-fns';
import {fastMerge, Str} from 'expensify-common';
import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxInputValue, OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
-import type {PartialDeep, ValueOf} from 'type-fest';
+import type {PartialDeep, SetRequired, ValueOf} from 'type-fest';
import ReceiptGeneric from '@assets/images/receipt-generic.png';
import * as API from '@libs/API';
import type {
@@ -472,6 +472,39 @@ function getReceiptError(receipt: OnyxEntry, filename?: string, isScanR
: ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''}, errorKey);
}
+/** Helper function to get optimistic fields violations onyx data */
+function getFieldViolationsOnyxData(iouReport: OnyxTypes.Report): SetRequired {
+ const missingFields: OnyxTypes.ReportFieldsViolations = {};
+ const excludedFields = Object.values(CONST.REPORT_VIOLATIONS_EXCLUDED_FIELDS) as string[];
+
+ Object.values(iouReport.fieldList ?? {}).forEach((field) => {
+ if (excludedFields.includes(field.fieldID) || !!field.value || !!field.defaultValue) {
+ return;
+ }
+ // in case of missing field violation the empty object is indicator.
+ missingFields[field.fieldID] = {};
+ });
+
+ return {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT_VIOLATIONS}${iouReport.reportID}`,
+ value: {
+ fieldRequired: missingFields,
+ },
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT_VIOLATIONS}${iouReport.reportID}`,
+ value: null,
+ },
+ ],
+ };
+}
+
/** Builds the Onyx data for an expense */
function buildOnyxDataForMoneyRequest(
chatReport: OnyxTypes.OnyxInputOrEntry,
@@ -845,31 +878,6 @@ function buildOnyxDataForMoneyRequest(
});
}
- const missingFields: OnyxTypes.ReportFieldsViolations = {};
- const excludedFields = Object.values(CONST.REPORT_VIOLATIONS_EXCLUDED_FIELDS) as string[];
-
- Object.values(iouReport.fieldList ?? {}).forEach((field) => {
- if (excludedFields.includes(field.fieldID) || !!field.value) {
- return;
- }
- // in case of missing field violation the empty object is indicator.
- missingFields[field.fieldID] = {};
- });
-
- optimisticData.push({
- onyxMethod: Onyx.METHOD.SET,
- key: `${ONYXKEYS.COLLECTION.REPORT_VIOLATIONS}${iouReport.reportID}`,
- value: {
- fieldRequired: missingFields,
- },
- });
-
- failureData.push({
- onyxMethod: Onyx.METHOD.SET,
- key: `${ONYXKEYS.COLLECTION.REPORT_VIOLATIONS}${iouReport.reportID}`,
- value: null,
- });
-
// We don't need to compute violations unless we're on a paid policy
if (!policy || !PolicyUtils.isPaidGroupPolicy(policy)) {
return [optimisticData, successData, failureData];
@@ -894,6 +902,13 @@ function buildOnyxDataForMoneyRequest(
});
}
+ // Show field violations only for control policies
+ if (PolicyUtils.isControlPolicy(policy)) {
+ const {optimisticData: fieldViolationsOptimisticData, failureData: fieldViolationsFailureData} = getFieldViolationsOnyxData(iouReport);
+ optimisticData.push(...fieldViolationsOptimisticData);
+ failureData.push(...fieldViolationsFailureData);
+ }
+
return [optimisticData, successData, failureData];
}
@@ -1638,6 +1653,13 @@ function buildOnyxDataForTrackExpense(
});
}
+ // Show field violations only for control policies
+ if (PolicyUtils.isControlPolicy(policy) && iouReport) {
+ const {optimisticData: fieldViolationsOptimisticData, failureData: fieldViolationsFailureData} = getFieldViolationsOnyxData(iouReport);
+ optimisticData.push(...fieldViolationsOptimisticData);
+ failureData.push(...fieldViolationsFailureData);
+ }
+
return [optimisticData, successData, failureData];
}
@@ -3583,7 +3605,7 @@ function sendInvoice(
accountID: currentUserAccountID,
amount: transaction?.amount ?? 0,
currency: transaction?.currency ?? '',
- comment: transaction?.comment?.comment ? transaction.comment.comment.trim() : '',
+ comment: transaction?.comment?.comment?.trim() ?? '',
merchant: transaction?.merchant ?? '',
category: transaction?.category,
date: transaction?.created ?? '',
@@ -4797,7 +4819,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
},
];
- const splitParticipants: Split[] = updatedTransaction?.comment.splits ?? [];
+ const splitParticipants: Split[] = updatedTransaction?.comment?.splits ?? [];
const amount = updatedTransaction?.modifiedAmount;
const currency = updatedTransaction?.modifiedCurrency;
console.debug(updatedTransaction);
@@ -4859,7 +4881,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
isPolicyExpenseChat ? -splitAmount : splitAmount,
currency ?? '',
oneOnOneIOUReport?.reportID ?? '-1',
- updatedTransaction?.comment.comment,
+ updatedTransaction?.comment?.comment,
updatedTransaction?.modifiedCreated,
CONST.IOU.TYPE.SPLIT,
transactionID,
@@ -4880,7 +4902,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
CONST.IOU.REPORT_ACTION_TYPE.CREATE,
splitAmount,
currency ?? '',
- updatedTransaction?.comment.comment ?? '',
+ updatedTransaction?.comment?.comment ?? '',
currentUserEmailForIOUSplit,
[participant],
oneOnOneTransaction.transactionID,
@@ -6829,6 +6851,13 @@ function hasIOUToApproveOrPay(chatReport: OnyxEntry, excludedI
});
}
+function isLastApprover(approvalChain: string[]): boolean {
+ if (approvalChain.length === 0) {
+ return true;
+ }
+ return approvalChain[approvalChain.length - 1] === currentUserEmail;
+}
+
function approveMoneyRequest(expenseReport: OnyxEntry, full?: boolean) {
if (expenseReport?.policyID && SubscriptionUtils.shouldRestrictUserBillableActions(expenseReport.policyID)) {
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(expenseReport.policyID));
@@ -6842,7 +6871,13 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?:
total = expenseReport?.unheldTotal;
}
const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(total, expenseReport?.currency ?? '', expenseReport?.reportID ?? '-1');
- const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, CONST.REPORT.STATUS_NUM.APPROVED);
+
+ const approvalChain = ReportUtils.getApprovalChain(PolicyUtils.getPolicy(expenseReport?.policyID), expenseReport?.ownerAccountID ?? -1, expenseReport?.total ?? 0);
+
+ const predictedNextStatus = isLastApprover(approvalChain) ? CONST.REPORT.STATUS_NUM.APPROVED : CONST.REPORT.STATUS_NUM.SUBMITTED;
+ const predictedNextState = isLastApprover(approvalChain) ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED;
+
+ const optimisticNextStep = NextStepUtils.buildNextStep(expenseReport, predictedNextStatus);
const chatReport = getReportOrDraftReport(expenseReport?.chatReportID);
const optimisticReportActionsData: OnyxUpdate = {
@@ -6862,8 +6897,8 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?:
...expenseReport,
lastMessageText: ReportActionsUtils.getReportActionText(optimisticApprovedReportAction),
lastMessageHtml: ReportActionsUtils.getReportActionHtml(optimisticApprovedReportAction),
- stateNum: CONST.REPORT.STATE_NUM.APPROVED,
- statusNum: CONST.REPORT.STATUS_NUM.APPROVED,
+ stateNum: predictedNextState,
+ statusNum: predictedNextStatus,
pendingFields: {
partial: full ? null : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
@@ -6951,7 +6986,7 @@ function approveMoneyRequest(expenseReport: OnyxEntry, full?:
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${heldTransaction.transactionID}`,
value: {
comment: {
- hold: heldTransaction.comment.hold,
+ hold: heldTransaction.comment?.hold,
},
},
});
diff --git a/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.ts b/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.ts
index f8d887fec47a..5bb51f22d64a 100644
--- a/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.ts
+++ b/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.ts
@@ -2,7 +2,6 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import * as API from '@libs/API';
import {WRITE_COMMANDS} from '@libs/API/types';
-import {getDefaultCompanyWebsite} from '@libs/BankAccountUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
@@ -18,7 +17,7 @@ Onyx.connect({
/**
* Reset user's reimbursement account. This will delete the bank account.
*/
-function resetFreePlanBankAccount(bankAccountID: number | undefined, session: OnyxEntry, policyID: string, user: OnyxEntry) {
+function resetFreePlanBankAccount(bankAccountID: number | undefined, session: OnyxEntry, policyID: string) {
if (!bankAccountID) {
throw new Error('Missing bankAccountID when attempting to reset free plan bank account');
}
@@ -98,7 +97,7 @@ function resetFreePlanBankAccount(bankAccountID: number | undefined, session: On
[INPUT_IDS.BUSINESS_INFO_STEP.STATE]: '',
[INPUT_IDS.BUSINESS_INFO_STEP.ZIP_CODE]: '',
[INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_PHONE]: '',
- [INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_WEBSITE]: getDefaultCompanyWebsite(session, user),
+ [INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_WEBSITE]: undefined,
[INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_TAX_ID]: '',
[INPUT_IDS.BUSINESS_INFO_STEP.INCORPORATION_TYPE]: '',
[INPUT_IDS.BUSINESS_INFO_STEP.INCORPORATION_DATE]: '',
diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts
index a71310119ab4..6f29382f25a8 100644
--- a/src/libs/actions/Session/index.ts
+++ b/src/libs/actions/Session/index.ts
@@ -677,7 +677,7 @@ function clearSignInData() {
*/
function resetHomeRouteParams() {
Navigation.isNavigationReady().then(() => {
- const routes = navigationRef.current?.getState().routes;
+ const routes = navigationRef.current?.getState()?.routes;
const homeRoute = routes?.find((route) => route.name === SCREENS.HOME);
const emptyParams: Record = {};
diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts
index 56affbab9de6..5e0b83f8521d 100644
--- a/src/libs/actions/User.ts
+++ b/src/libs/actions/User.ts
@@ -36,7 +36,7 @@ import Visibility from '@libs/Visibility';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
-import type {BlockedFromConcierge, CustomStatusDraft, Policy} from '@src/types/onyx';
+import type {BlockedFromConcierge, CustomStatusDraft, LoginList, Policy} from '@src/types/onyx';
import type Login from '@src/types/onyx/Login';
import type {OnyxServerUpdate} from '@src/types/onyx/OnyxUpdatesFromServer';
import type OnyxPersonalDetails from '@src/types/onyx/PersonalDetails';
@@ -70,6 +70,13 @@ Onyx.connect({
},
});
+let allPolicies: OnyxCollection;
+Onyx.connect({
+ key: ONYXKEYS.COLLECTION.POLICY,
+ waitForCollectionCallback: true,
+ callback: (value) => (allPolicies = value),
+});
+
/**
* Attempt to close the user's accountt
*/
@@ -365,7 +372,7 @@ function validateLogin(accountID: number, validateCode: string) {
/**
* Validates a secondary login / contact method
*/
-function validateSecondaryLogin(contactMethod: string, validateCode: string) {
+function validateSecondaryLogin(loginList: OnyxEntry, contactMethod: string, validateCode: string) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
@@ -420,6 +427,70 @@ function validateSecondaryLogin(contactMethod: string, validateCode: string) {
},
},
];
+ // If the primary login isn't validated yet, set the secondary login as the primary login
+ if (!loginList?.[currentEmail].validatedDate) {
+ successData.push(
+ ...[
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.ACCOUNT,
+ value: {
+ primaryLogin: contactMethod,
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.SESSION,
+ value: {
+ email: contactMethod,
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.PERSONAL_DETAILS_LIST,
+ value: {
+ [currentUserAccountID]: {
+ login: contactMethod,
+ displayName: PersonalDetailsUtils.createDisplayName(contactMethod, myPersonalDetails),
+ },
+ },
+ },
+ ],
+ );
+
+ Object.values(allPolicies ?? {}).forEach((policy) => {
+ if (!policy) {
+ return;
+ }
+
+ let optimisticPolicyDataValue;
+
+ if (policy.employeeList) {
+ const currentEmployee = policy.employeeList[currentEmail];
+ optimisticPolicyDataValue = {
+ employeeList: {
+ [currentEmail]: null,
+ [contactMethod]: currentEmployee,
+ },
+ };
+ }
+
+ if (policy.ownerAccountID === currentUserAccountID) {
+ optimisticPolicyDataValue = {
+ ...optimisticPolicyDataValue,
+ owner: contactMethod,
+ };
+ }
+
+ if (optimisticPolicyDataValue) {
+ successData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policy.id}`,
+ value: optimisticPolicyDataValue,
+ });
+ }
+ });
+ }
const failureData: OnyxUpdate[] = [
{
@@ -765,7 +836,7 @@ function generateStatementPDF(period: string) {
/**
* Sets a contact method / secondary login as the user's "Default" contact method.
*/
-function setContactMethodAsDefault(newDefaultContactMethod: string, policies: OnyxCollection>) {
+function setContactMethodAsDefault(newDefaultContactMethod: string) {
const oldDefaultContactMethod = currentEmail;
const optimisticData: OnyxUpdate[] = [
{
@@ -858,7 +929,7 @@ function setContactMethodAsDefault(newDefaultContactMethod: string, policies: On
},
];
- Object.values(policies ?? {}).forEach((policy) => {
+ Object.values(allPolicies ?? {}).forEach((policy) => {
if (!policy) {
return;
}
diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts
index c691763ef8cf..d54314ae6f05 100644
--- a/src/libs/actions/Welcome.ts
+++ b/src/libs/actions/Welcome.ts
@@ -15,6 +15,7 @@ type OnboardingData = Onboarding | [] | undefined;
let isLoadingReportData = true;
let tryNewDotData: TryNewDot | undefined;
+let onboarding: OnboardingData;
type HasCompletedOnboardingFlowProps = {
onCompleted?: () => void;
@@ -31,8 +32,8 @@ let isServerDataReadyPromise = new Promise((resolve) => {
resolveIsReadyPromise = resolve;
});
-let resolveOnboardingFlowStatus: (value?: OnboardingData) => void;
-let isOnboardingFlowStatusKnownPromise = new Promise((resolve) => {
+let resolveOnboardingFlowStatus: () => void;
+let isOnboardingFlowStatusKnownPromise = new Promise((resolve) => {
resolveOnboardingFlowStatus = resolve;
});
@@ -46,7 +47,7 @@ function onServerDataReady(): Promise {
}
function isOnboardingFlowCompleted({onCompleted, onNotCompleted}: HasCompletedOnboardingFlowProps) {
- isOnboardingFlowStatusKnownPromise.then((onboarding) => {
+ isOnboardingFlowStatusKnownPromise.then(() => {
if (Array.isArray(onboarding) || onboarding?.hasCompletedGuidedSetupFlow === undefined) {
return;
}
@@ -124,6 +125,17 @@ function checkTryNewDotDataReady() {
resolveTryNewDotStatus?.();
}
+/**
+ * Check if the onboarding data is loaded
+ */
+function checkOnboardingDataReady() {
+ if (onboarding === undefined) {
+ return;
+ }
+
+ resolveOnboardingFlowStatus();
+}
+
function setOnboardingPurposeSelected(value: OnboardingPurposeType) {
Onyx.set(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, value ?? null);
}
@@ -171,13 +183,8 @@ function completeHybridAppOnboarding() {
Onyx.connect({
key: ONYXKEYS.NVP_ONBOARDING,
callback: (value) => {
- if (value === undefined) {
- return;
- }
- resolveOnboardingFlowStatus(value);
- isOnboardingFlowStatusKnownPromise = new Promise((resolve) => {
- resolveOnboardingFlowStatus = resolve;
- });
+ onboarding = value;
+ checkOnboardingDataReady();
},
});
@@ -202,7 +209,7 @@ function resetAllChecks() {
isServerDataReadyPromise = new Promise((resolve) => {
resolveIsReadyPromise = resolve;
});
- isOnboardingFlowStatusKnownPromise = new Promise((resolve) => {
+ isOnboardingFlowStatusKnownPromise = new Promise((resolve) => {
resolveOnboardingFlowStatus = resolve;
});
isLoadingReportData = true;
diff --git a/src/libs/fileDownload/getAttachmentDetails.ts b/src/libs/fileDownload/getAttachmentDetails.ts
index 5787979a3795..1b0abc73a50d 100644
--- a/src/libs/fileDownload/getAttachmentDetails.ts
+++ b/src/libs/fileDownload/getAttachmentDetails.ts
@@ -10,7 +10,7 @@ const getAttachmentDetails: GetAttachmentDetails = (html) => {
const IS_IMAGE_TAG = //i.test(html);
const PREVIEW_SOURCE_REGEX = new RegExp(`${CONST.ATTACHMENT_PREVIEW_ATTRIBUTE}*=*"(.+?)"`, 'i');
const SOURCE_REGEX = new RegExp(`${CONST.ATTACHMENT_SOURCE_ATTRIBUTE}*=*"(.+?)"`, 'i');
- const ORIGINAL_FILENAME_REGEX = IS_IMAGE_TAG ? new RegExp(`${CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE}*=*"(.+?)"`, 'i') : new RegExp(']*>([^<]+)', 'i');
+ const ORIGINAL_FILENAME_REGEX = IS_IMAGE_TAG ? new RegExp(`${CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE}*=*"(.+?)"`, 'i') : new RegExp('<(?:a|video)[^>]*>([^<]+)(?:a|video)>', 'i');
if (!html) {
return {
previewSourceURL: null,
diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx
index 541e47f6cb10..a425c776f63d 100644
--- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx
+++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx
@@ -1,4 +1,4 @@
-import React, {useCallback, useEffect, useMemo} from 'react';
+import React, {useCallback, useMemo} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import FormProvider from '@components/Form/FormProvider';
@@ -12,7 +12,6 @@ import type {SubStepProps} from '@hooks/useSubStep/types';
import useThemeStyles from '@hooks/useThemeStyles';
import {getDefaultCompanyWebsite} from '@libs/BankAccountUtils';
import * as ValidationUtils from '@libs/ValidationUtils';
-import * as BankAccounts from '@userActions/BankAccounts';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
@@ -59,10 +58,6 @@ function WebsiteBusiness({reimbursementAccount, user, session, onNext, isEditing
shouldSaveDraft: isEditing,
});
- useEffect(() => {
- BankAccounts.addBusinessWebsiteForDraft(defaultCompanyWebsite);
- }, [defaultCompanyWebsite]);
-
return (
member.accountID === accountID.toString());
- const isSelected = selectedMembers.includes(accountID);
+ const isSelected = selectedMembers.includes(accountID) && canSelectMultiple;
const isAdmin = role === CONST.REPORT.ROLE.ADMIN;
let roleBadge = null;
if (isAdmin) {
@@ -107,7 +107,7 @@ function ReportParticipantsPage({report}: WithReportOrNotFoundProps) {
result = result.sort((a, b) => (a.text ?? '').toLowerCase().localeCompare((b.text ?? '').toLowerCase()));
return result;
- }, [formatPhoneNumber, personalDetails, report, selectedMembers, currentUserAccountID, translate, isGroupChat, isIOUReport]);
+ }, [formatPhoneNumber, personalDetails, report, selectedMembers, currentUserAccountID, translate, isGroupChat, isIOUReport, canSelectMultiple]);
const participants = useMemo(() => getUsers(), [getUsers]);
diff --git a/src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx b/src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx
index b8880f372809..89b5dcdd8a2b 100644
--- a/src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx
+++ b/src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx
@@ -1,6 +1,5 @@
import React, {useCallback} from 'react';
import {View} from 'react-native';
-import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Illustrations from '@components/Icon/Illustrations';
@@ -9,11 +8,11 @@ import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as PolicyUtils from '@libs/PolicyUtils';
import variables from '@styles/variables';
-import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
type WorkspaceAdminRestrictedActionProps = {
@@ -22,7 +21,7 @@ type WorkspaceAdminRestrictedActionProps = {
function WorkspaceAdminRestrictedAction({policyID}: WorkspaceAdminRestrictedActionProps) {
const {translate} = useLocalize();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const styles = useThemeStyles();
const openAdminsReport = useCallback(() => {
diff --git a/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx b/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx
index 42b1e64d8282..a9cee3236ad0 100644
--- a/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx
+++ b/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx
@@ -1,6 +1,7 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import {useOnyx} from 'react-native-onyx';
+import usePolicy from '@hooks/usePolicy';
import type {RestrictedActionParamList} from '@libs/Navigation/types';
import * as PolicyUtils from '@libs/PolicyUtils';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
@@ -18,7 +19,7 @@ function WorkspaceRestrictedActionPage({
},
}: WorkspaceRestrictedActionPageProps) {
const [session] = useOnyx(ONYXKEYS.SESSION);
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
// Workspace Owner
if (PolicyUtils.isPolicyOwner(policy, session?.accountID ?? -1)) {
diff --git a/src/pages/RestrictedAction/Workspace/WorkspaceUserRestrictedAction.tsx b/src/pages/RestrictedAction/Workspace/WorkspaceUserRestrictedAction.tsx
index 4d2aabd8774e..386dd96523ed 100644
--- a/src/pages/RestrictedAction/Workspace/WorkspaceUserRestrictedAction.tsx
+++ b/src/pages/RestrictedAction/Workspace/WorkspaceUserRestrictedAction.tsx
@@ -1,6 +1,5 @@
import React, {useCallback} from 'react';
import {View} from 'react-native';
-import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Illustrations from '@components/Icon/Illustrations';
@@ -9,11 +8,11 @@ import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportUtils from '@libs/ReportUtils';
import variables from '@styles/variables';
-import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
type WorkspaceUserRestrictedActionProps = {
@@ -22,7 +21,7 @@ type WorkspaceUserRestrictedActionProps = {
function WorkspaceUserRestrictedAction({policyID}: WorkspaceUserRestrictedActionProps) {
const {translate} = useLocalize();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const styles = useThemeStyles();
const openPolicyExpenseReport = useCallback(() => {
diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx
index ee9e06e186af..c61166f10c6d 100644
--- a/src/pages/Travel/ManageTrips.tsx
+++ b/src/pages/Travel/ManageTrips.tsx
@@ -7,6 +7,7 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import * as Illustrations from '@components/Icon/Illustrations';
import ScrollView from '@components/ScrollView';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
@@ -34,7 +35,7 @@ function ManageTrips() {
const {translate} = useLocalize();
const [travelSettings] = useOnyx(ONYXKEYS.NVP_TRAVEL_SETTINGS);
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`);
+ const policy = usePolicy(activePolicyID);
const [ctaErrorMessage, setCtaErrorMessage] = useState('');
diff --git a/src/pages/ValidateLoginPage/index.website.tsx b/src/pages/ValidateLoginPage/index.website.tsx
index b7d46b88faaa..13f636867852 100644
--- a/src/pages/ValidateLoginPage/index.website.tsx
+++ b/src/pages/ValidateLoginPage/index.website.tsx
@@ -1,5 +1,5 @@
import React, {useEffect} from 'react';
-import {useOnyx} from 'react-native-onyx';
+import {withOnyx} from 'react-native-onyx';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import ExpiredValidateCodeModal from '@components/ValidateCode/ExpiredValidateCodeModal';
import JustSignedInModal from '@components/ValidateCode/JustSignedInModal';
@@ -12,13 +12,13 @@ import ONYXKEYS from '@src/ONYXKEYS';
import type {ValidateLoginPageOnyxProps, ValidateLoginPageProps} from './types';
function ValidateLoginPage({
+ account,
+ credentials,
route: {
params: {accountID, validateCode, exitTo},
},
+ session,
}: ValidateLoginPageProps) {
- const [session] = useOnyx(ONYXKEYS.SESSION);
- const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS);
- const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const login = credentials?.login;
const autoAuthState = session?.autoAuthState ?? CONST.AUTO_AUTH_STATE.NOT_STARTED;
const isSignedIn = !!session?.authToken && session?.authTokenType !== CONST.AUTH_TOKEN_TYPES.ANONYMOUS;
@@ -87,4 +87,8 @@ function ValidateLoginPage({
ValidateLoginPage.displayName = 'ValidateLoginPage';
-export default ValidateLoginPage;
+export default withOnyx, ValidateLoginPageOnyxProps>({
+ account: {key: ONYXKEYS.ACCOUNT},
+ credentials: {key: ONYXKEYS.CREDENTIALS},
+ session: {key: ONYXKEYS.SESSION},
+})(ValidateLoginPage);
diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx
index 5af4e30f07f1..24d73ddeb9a5 100644
--- a/src/pages/home/ReportScreen.tsx
+++ b/src/pages/home/ReportScreen.tsx
@@ -403,12 +403,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const isLoading = isLoadingApp || !reportIDFromRoute || (!isSidebarLoaded && !isInNarrowPaneModal) || PersonalDetailsUtils.isPersonalDetailsEmpty();
const shouldShowSkeleton =
- (isLinkingToMessage && !isLinkedMessagePageReady) ||
- (!!reportActionIDFromRoute && !!reportMetadata?.isLoadingInitialReportActions) ||
- (!isLinkingToMessage && !isInitialPageReady) ||
- isLoadingReportOnyx ||
- !isCurrentReportLoadedFromOnyx ||
- isLoading;
+ (isLinkingToMessage && !isLinkedMessagePageReady) || (!isLinkingToMessage && !isInitialPageReady) || isLoadingReportOnyx || !isCurrentReportLoadedFromOnyx || isLoading;
// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundLinkedAction =
@@ -789,7 +784,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
hasLoadingNewerReportActionsError={reportMetadata?.hasLoadingNewerReportActionsError}
isLoadingOlderReportActions={reportMetadata?.isLoadingOlderReportActions}
hasLoadingOlderReportActionsError={reportMetadata?.hasLoadingOlderReportActionsError}
- isReadyForCommentLinking={!shouldShowSkeleton}
transactionThreadReportID={transactionThreadReportID}
/>
)}
diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx
index 457076b19701..58e361d74293 100755
--- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx
+++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx
@@ -14,6 +14,7 @@ import useEnvironment from '@hooks/useEnvironment';
import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePaginatedReportActions from '@hooks/usePaginatedReportActions';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
@@ -141,13 +142,64 @@ function BaseReportActionContextMenu({
const [download] = useOnyx(`${ONYXKEYS.COLLECTION.DOWNLOAD}${sourceID}`);
+ const childReport = ReportUtils.getReport(reportAction?.childReportID ?? '-1');
+ const parentReportAction = ReportActionsUtils.getReportAction(childReport?.parentReportID ?? '', childReport?.parentReportActionID ?? '');
+ const {reportActions: paginatedReportActions} = usePaginatedReportActions(childReport?.reportID ?? '-1');
+
+ const transactionThreadReportID = useMemo(
+ () => ReportActionsUtils.getOneTransactionThreadReportID(childReport?.reportID ?? '-1', paginatedReportActions ?? [], isOffline),
+ [childReport?.reportID, paginatedReportActions, isOffline],
+ );
+
+ const [transactionThreadReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`);
+
+ const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(childReport), [childReport]);
+ const isInvoiceReport = useMemo(() => ReportUtils.isInvoiceReport(childReport), [childReport]);
+
+ const requestParentReportAction = useMemo(() => {
+ if (isMoneyRequestReport || isInvoiceReport) {
+ if (!paginatedReportActions || !transactionThreadReport?.parentReportActionID) {
+ return undefined;
+ }
+ return paginatedReportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID);
+ }
+ return parentReportAction;
+ }, [parentReportAction, isMoneyRequestReport, isInvoiceReport, paginatedReportActions, transactionThreadReport?.parentReportActionID]);
+
+ const moneyRequestAction = transactionThreadReportID ? requestParentReportAction : parentReportAction;
+
+ const [parentReportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${childReport?.parentReportID ?? '-1'}`);
+ const parentReport = ReportUtils.getReport(childReport?.parentReportID ?? '-1');
+
+ const isMoneyRequest = useMemo(() => ReportUtils.isMoneyRequest(childReport), [childReport]);
+ const isTrackExpenseReport = ReportUtils.isTrackExpenseReport(childReport);
+ const isSingleTransactionView = isMoneyRequest || isTrackExpenseReport;
+ const isMoneyRequestOrReport = isMoneyRequestReport || isInvoiceReport || isSingleTransactionView;
+
+ const areHoldRequirementsMet = isMoneyRequestOrReport && !ReportUtils.isArchivedRoom(transactionThreadReportID ? childReport : parentReport, parentReportNameValuePairs);
+
const originalReportID = useMemo(() => ReportUtils.getOriginalReportID(reportID, reportAction), [reportID, reportAction]);
const shouldEnableArrowNavigation = !isMini && (isVisible || shouldKeepOpen);
let filteredContextMenuActions = ContextMenuActions.filter(
(contextAction) =>
!disabledActions.includes(contextAction) &&
- contextAction.shouldShow(type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID, isPinnedChat, isUnreadChat, !!isOffline, isMini, isProduction),
+ contextAction.shouldShow(
+ type,
+ reportAction,
+ isArchivedRoom,
+ betas,
+ anchor,
+ isChronosReport,
+ reportID,
+ isPinnedChat,
+ isUnreadChat,
+ !!isOffline,
+ isMini,
+ isProduction,
+ moneyRequestAction,
+ areHoldRequirementsMet,
+ ),
);
if (isMini) {
@@ -254,6 +306,7 @@ function BaseReportActionContextMenu({
interceptAnonymousUser,
openOverflowMenu,
setIsEmojiPickerActive,
+ moneyRequestAction,
};
if ('renderContent' in contextAction) {
diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx
index e2a25ac4b30b..aec92fd360e9 100644
--- a/src/pages/home/report/ContextMenu/ContextMenuActions.tsx
+++ b/src/pages/home/report/ContextMenu/ContextMenuActions.tsx
@@ -67,6 +67,8 @@ type ShouldShow = (
isOffline: boolean,
isMini: boolean,
isProduction: boolean,
+ moneyRequestAction: ReportAction | undefined,
+ areHoldRequirementsMet: boolean,
) => boolean;
type ContextMenuActionPayload = {
@@ -84,6 +86,7 @@ type ContextMenuActionPayload = {
event?: GestureResponderEvent | MouseEvent | KeyboardEvent;
setIsEmojiPickerActive?: (state: boolean) => void;
anchorRef?: MutableRefObject;
+ moneyRequestAction: ReportAction | undefined;
};
type OnPress = (closePopover: boolean, payload: ContextMenuActionPayload, selection?: string, reportID?: string, draftMessage?: string) => void;
@@ -262,18 +265,32 @@ const ContextMenuActions: ContextMenuAction[] = [
},
{
isAnonymousAction: false,
- textTranslateKey: 'iou.unholdExpense',
+ textTranslateKey: 'iou.unhold',
icon: Expensicons.Stopwatch,
- shouldShow: (type, reportAction) =>
- type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canEditReportAction(reportAction) && ReportUtils.canHoldUnholdReportAction(reportAction).canUnholdRequest,
- onPress: (closePopover, {reportAction}) => {
+ shouldShow: (
+ type,
+ reportAction,
+ isArchivedRoom,
+ betas,
+ anchor,
+ isChronosReport,
+ reportID,
+ isPinnedChat,
+ isUnreadChat,
+ isOffline,
+ isMini,
+ isProduction,
+ moneyRequestAction,
+ areHoldRequirementsMet,
+ ) => type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && areHoldRequirementsMet && ReportUtils.canHoldUnholdReportAction(moneyRequestAction).canUnholdRequest,
+ onPress: (closePopover, {moneyRequestAction}) => {
if (closePopover) {
- hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(reportAction));
+ hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction));
return;
}
// No popover to hide, call changeMoneyRequestHoldStatus immediately
- ReportUtils.changeMoneyRequestHoldStatus(reportAction);
+ ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction);
},
getDescription: () => {},
},
@@ -281,16 +298,30 @@ const ContextMenuActions: ContextMenuAction[] = [
isAnonymousAction: false,
textTranslateKey: 'iou.hold',
icon: Expensicons.Stopwatch,
- shouldShow: (type, reportAction) =>
- type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canEditReportAction(reportAction) && ReportUtils.canHoldUnholdReportAction(reportAction).canHoldRequest,
- onPress: (closePopover, {reportAction}) => {
+ shouldShow: (
+ type,
+ reportAction,
+ isArchivedRoom,
+ betas,
+ anchor,
+ isChronosReport,
+ reportID,
+ isPinnedChat,
+ isUnreadChat,
+ isOffline,
+ isMini,
+ isProduction,
+ moneyRequestAction,
+ areHoldRequirementsMet,
+ ) => type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && areHoldRequirementsMet && ReportUtils.canHoldUnholdReportAction(moneyRequestAction).canHoldRequest,
+ onPress: (closePopover, {moneyRequestAction}) => {
if (closePopover) {
- hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(reportAction));
+ hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction));
return;
}
// No popover to hide, call changeMoneyRequestHoldStatus immediately
- ReportUtils.changeMoneyRequestHoldStatus(reportAction);
+ ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction);
},
getDescription: () => {},
},
@@ -303,9 +334,10 @@ const ContextMenuActions: ContextMenuAction[] = [
const isDeletedAction = ReportActionsUtils.isDeletedAction(reportAction);
const shouldDisplayThreadReplies = ReportUtils.shouldDisplayThreadReplies(reportAction, reportID);
const subscribed = childReportNotificationPreference !== 'hidden';
- const isCommentAction = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !ReportUtils.isThreadFirstChat(reportAction, reportID);
- const isWhisperAction = ReportActionsUtils.isWhisperAction(reportAction);
- return !subscribed && !isWhisperAction && isCommentAction && (!isDeletedAction || shouldDisplayThreadReplies);
+ const isThreadFirstChat = ReportUtils.isThreadFirstChat(reportAction, reportID);
+ const isWhisperAction = ReportActionsUtils.isWhisperAction(reportAction) || ReportActionsUtils.isActionableTrackExpense(reportAction);
+ const isExpenseReportAction = ReportActionsUtils.isMoneyRequestAction(reportAction) || ReportActionsUtils.isReportPreviewAction(reportAction);
+ return !subscribed && !isWhisperAction && !isExpenseReportAction && !isThreadFirstChat && (shouldDisplayThreadReplies || (!isDeletedAction && !isArchivedRoom));
},
onPress: (closePopover, {reportAction, reportID}) => {
const childReportNotificationPreference = ReportUtils.getChildReportNotificationPreference(reportAction);
diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx
index beebccd131b3..c698cefe3349 100644
--- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx
+++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx
@@ -1,5 +1,5 @@
import type {ForwardedRef} from 'react';
-import React, {forwardRef, useEffect} from 'react';
+import React, {forwardRef, useEffect, useRef} from 'react';
import {Keyboard} from 'react-native';
import E2EClient from '@libs/E2E/client';
import type {ComposerRef} from '@pages/home/report/ReportActionCompose/ReportActionCompose';
@@ -24,6 +24,8 @@ function ComposerWithSuggestionsE2e(props: ComposerWithSuggestionsProps, ref: Fo
// for this component. This file is only used for e2e tests, so it's okay to
// disable compiler for this file.
+ const textInputRef = useRef();
+
// Eventually Auto focus on e2e tests
useEffect(() => {
const testConfig = E2EClient.getCurrentActiveTestConfig();
@@ -34,11 +36,11 @@ function ComposerWithSuggestionsE2e(props: ComposerWithSuggestionsProps, ref: Fo
// We need to wait for the component to be mounted before focusing
setTimeout(() => {
const setFocus = () => {
- if (!(ref && 'current' in ref)) {
+ if (!(textInputRef && 'current' in textInputRef)) {
return;
}
- ref.current?.focus(true);
+ textInputRef.current?.focus(true);
setTimeout(() => {
// and actually let's verify that the keyboard is visible
@@ -46,21 +48,27 @@ function ComposerWithSuggestionsE2e(props: ComposerWithSuggestionsProps, ref: Fo
return;
}
- ref.current?.blur();
+ textInputRef.current?.blur();
setFocus();
- // 500ms is enough time for any keyboard to open
- }, 500);
+ // 1000ms is enough time for any keyboard to open
+ }, 1000);
};
setFocus();
}, 1);
- }, [ref]);
+ }, [textInputRef]);
return (
{
+ textInputRef.current = composerRef;
+
+ if (typeof ref === 'function') {
+ ref(composerRef);
+ }
+ }}
>
{/* Important:
this has to be a child, as this container might not
diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx
index 7d1f27920bdf..d5aa07c3b2db 100644
--- a/src/pages/home/report/ReportActionItemContentCreated.tsx
+++ b/src/pages/home/report/ReportActionItemContentCreated.tsx
@@ -13,6 +13,7 @@ import type {ShowContextMenuContextProps} from '@components/ShowContextMenuConte
import SpacerView from '@components/SpacerView';
import UnreadActionIndicator from '@components/UnreadActionIndicator';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
@@ -52,7 +53,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans
const {report, action, transactionThreadReport} = contextValue;
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report.policyID === CONST.POLICY.OWNER_EMAIL_FAKE ? '-1' : report.policyID ?? '-1'}`);
+ const policy = usePolicy(report.policyID === CONST.POLICY.OWNER_EMAIL_FAKE ? '-1' : report.policyID ?? '-1');
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID ?? '-1'}`);
const transactionCurrency = TransactionUtils.getCurrency(transaction);
diff --git a/src/pages/home/report/ReportActionItemParentAction.tsx b/src/pages/home/report/ReportActionItemParentAction.tsx
index cba0f1572fd4..41943485f171 100644
--- a/src/pages/home/report/ReportActionItemParentAction.tsx
+++ b/src/pages/home/report/ReportActionItemParentAction.tsx
@@ -10,8 +10,6 @@ import onyxSubscribe from '@libs/onyxSubscribe';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as Report from '@userActions/Report';
-import Timing from '@userActions/Timing';
-import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
@@ -135,7 +133,6 @@ function ReportActionItemParentAction({
// Pop the chat report screen before navigating to the linked report action.
Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '-1', ancestor.reportAction.reportActionID));
}
- Timing.start(CONST.TIMING.SWITCH_REPORT);
}
: undefined
}
diff --git a/src/pages/home/report/ReportActionItemThread.tsx b/src/pages/home/report/ReportActionItemThread.tsx
index 5d2c6316df4e..d18adf6ba0d2 100644
--- a/src/pages/home/report/ReportActionItemThread.tsx
+++ b/src/pages/home/report/ReportActionItemThread.tsx
@@ -46,7 +46,7 @@ function ReportActionItemThread({numberOfReplies, icons, mostRecentReply, childR
{
Report.navigateToAndOpenChildReport(childReportID);
- Timing.start(CONST.TIMING.SWITCH_REPORT);
+ Timing.start(CONST.TIMING.SWITCH_REPORT_THREAD);
}}
role={CONST.ROLE.BUTTON}
accessibilityLabel={`${numberOfReplies} ${replyText}`}
diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx
index 12d886cd30f9..1985b9f0a134 100644
--- a/src/pages/home/report/ReportActionsList.tsx
+++ b/src/pages/home/report/ReportActionsList.tsx
@@ -177,8 +177,17 @@ function ReportActionsList({
const userActiveSince = useRef(null);
const lastMessageTime = useRef(null);
- const [isVisible, setIsVisible] = useState(false);
+ const [isVisible, setIsVisible] = useState(Visibility.isVisible());
const isFocused = useIsFocused();
+ const hasCalledReadNewestAction = useRef(false);
+
+ useEffect(() => {
+ /**
+ * This allows to mark the report as read, when
+ * report is opened and new report actions are received.
+ */
+ hasCalledReadNewestAction.current = false;
+ }, [reportActions]);
useEffect(() => {
const unsubscriber = Visibility.onVisibilityChange(() => {
@@ -267,6 +276,9 @@ function ReportActionsList({
if (!userActiveSince.current || report.reportID !== prevReportID) {
return;
}
+ if (hasCalledReadNewestAction.current) {
+ return;
+ }
if (ReportUtils.isUnread(report)) {
// On desktop, when the notification center is displayed, Visibility.isVisible() will return false.
// Currently, there's no programmatic way to dismiss the notification center panel.
@@ -274,6 +286,7 @@ function ReportActionsList({
const isFromNotification = route?.params?.referrer === CONST.REFERRER.NOTIFICATION;
if ((Visibility.isVisible() || isFromNotification) && scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD) {
Report.readNewestAction(report.reportID);
+ hasCalledReadNewestAction.current = true;
if (isFromNotification) {
Navigation.setParams({referrer: undefined});
}
@@ -523,7 +536,9 @@ function ReportActionsList({
if (!userActiveSince.current || report.reportID !== prevReportID) {
return;
}
-
+ if (hasCalledReadNewestAction.current) {
+ return;
+ }
if (!isVisible || !isFocused) {
if (!lastMessageTime.current) {
lastMessageTime.current = sortedVisibleReportActions[0]?.created ?? '';
@@ -535,15 +550,19 @@ function ReportActionsList({
// show marker based on report.lastReadTime
const newMessageTimeReference = lastMessageTime.current && report.lastReadTime && lastMessageTime.current > report.lastReadTime ? userActiveSince.current : report.lastReadTime;
lastMessageTime.current = null;
- if (
- scrollingVerticalOffset.current >= MSG_VISIBLE_THRESHOLD ||
- !sortedVisibleReportActions.some(
- (reportAction) =>
- newMessageTimeReference &&
- newMessageTimeReference < reportAction.created &&
- (ReportActionsUtils.isReportPreviewAction(reportAction) ? reportAction.childLastActorAccountID : reportAction.actorAccountID) !== Report.getCurrentUserAccountID(),
- )
- ) {
+ const areSomeReportActionsUnread = sortedVisibleReportActions.some((reportAction) => {
+ /**
+ * The archived reports should not be marked as unread. So we are checking if the report is archived or not.
+ * If the report is archived, we will mark the report as read.
+ */
+ const isArchivedReport = ReportUtils.isArchivedRoom(report);
+ const isUnread = isArchivedReport || (newMessageTimeReference && newMessageTimeReference < reportAction.created);
+ return (
+ isUnread && (ReportActionsUtils.isReportPreviewAction(reportAction) ? reportAction.childLastActorAccountID : reportAction.actorAccountID) !== Report.getCurrentUserAccountID()
+ );
+ });
+
+ if (scrollingVerticalOffset.current >= MSG_VISIBLE_THRESHOLD || !areSomeReportActionsUnread) {
return;
}
@@ -553,6 +572,7 @@ function ReportActionsList({
setCurrentUnreadMarker(null);
cacheUnreadMarkers.delete(report.reportID);
calculateUnreadMarker();
+ hasCalledReadNewestAction.current = true;
// This effect logic to `mark as read` will only run when the report focused has new messages and the App visibility
// is changed to visible(meaning user switched to app/web, while user was previously using different tab or application).
diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx
index fb99f8508f6f..bc725d0f44b5 100755
--- a/src/pages/home/report/ReportActionsView.tsx
+++ b/src/pages/home/report/ReportActionsView.tsx
@@ -71,9 +71,6 @@ type ReportActionsViewProps = ReportActionsViewOnyxProps & {
/** There an error when loading newer report actions */
hasLoadingNewerReportActionsError?: boolean;
- /** Whether the report is ready for comment linking */
- isReadyForCommentLinking?: boolean;
-
/** The reportID of the transaction thread report associated with this current report, if any */
// eslint-disable-next-line react/no-unused-prop-types
transactionThreadReportID?: string | null;
@@ -96,13 +93,13 @@ function ReportActionsView({
hasLoadingOlderReportActionsError = false,
isLoadingNewerReportActions = false,
hasLoadingNewerReportActionsError = false,
- isReadyForCommentLinking = false,
transactionThreadReportID,
}: ReportActionsViewProps) {
useCopySelectionHelper();
const reactionListRef = useContext(ReactionListContext);
const route = useRoute>();
const reportActionID = route?.params?.reportActionID;
+ const prevReportActionID = usePrevious(reportActionID);
const didLayout = useRef(false);
const didLoadOlderChats = useRef(false);
const didLoadNewerChats = useRef(false);
@@ -122,7 +119,6 @@ function ReportActionsView({
const [isNavigatingToLinkedMessage, setNavigatingToLinkedMessage] = useState(!!reportActionID);
const prevShouldUseNarrowLayoutRef = useRef(shouldUseNarrowLayout);
const reportID = report.reportID;
- const isLoading = (!!reportActionID && isLoadingInitialReportActions) || !isReadyForCommentLinking;
const isReportFullyVisible = useMemo((): boolean => getIsReportFullyVisible(isFocused), [isFocused]);
const openReportIfNecessary = () => {
if (!shouldFetchReport(report)) {
@@ -146,7 +142,7 @@ function ReportActionsView({
// Change the list ID only for comment linking to get the positioning right
const listID = useMemo(() => {
- if (!reportActionID) {
+ if (!reportActionID && !prevReportActionID) {
// Keep the old list ID since we're not in the Comment Linking flow
return listOldID;
}
@@ -156,7 +152,7 @@ function ReportActionsView({
listOldID = newID;
return newID;
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
- }, [route, isLoadingInitialReportActions, reportActionID]);
+ }, [route, reportActionID]);
// When we are offline before opening an IOU/Expense report,
// the total of the report and sometimes the expense aren't displayed because these actions aren't returned until `OpenReport` API is complete.
@@ -244,7 +240,7 @@ function ReportActionsView({
if (!reportActionID) {
return combinedReportActions;
}
- if (isLoading || indexOfLinkedAction === -1) {
+ if (indexOfLinkedAction === -1) {
return [];
}
@@ -256,7 +252,7 @@ function ReportActionsView({
// currentReportActionID is needed to trigger batching once the report action has been positioned
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
- }, [reportActionID, combinedReportActions, indexOfLinkedAction, isLoading, currentReportActionID]);
+ }, [reportActionID, combinedReportActions, indexOfLinkedAction, currentReportActionID]);
const reportActionIDMap = useMemo(() => {
const reportActionIDs = allReportActions.map((action) => action.reportActionID);
@@ -294,21 +290,6 @@ function ReportActionsView({
const hasMoreCached = reportActions.length < combinedReportActions.length;
const newestReportAction = useMemo(() => reportActions?.[0], [reportActions]);
- const handleReportActionPagination = useCallback(
- ({firstReportActionID}: {firstReportActionID: string}) => {
- // This function is a placeholder as the actual pagination is handled by visibleReportActions
- if (!hasMoreCached) {
- isFirstLinkedActionRender.current = false;
- fetchNewerAction(newestReportAction);
- }
- if (isFirstLinkedActionRender.current) {
- isFirstLinkedActionRender.current = false;
- }
- setCurrentReportActionID(firstReportActionID);
- },
- [fetchNewerAction, hasMoreCached, newestReportAction],
- );
-
const mostRecentIOUReportActionID = useMemo(() => ReportActionsUtils.getMostRecentIOURequestActionID(reportActions), [reportActions]);
const hasCachedActionOnFirstRender = useInitialValue(() => reportActions.length > 0);
const hasNewestReportAction = reportActions[0]?.created === report.lastVisibleActionCreated || reportActions[0]?.created === transactionThreadReport?.lastVisibleActionCreated;
@@ -343,6 +324,21 @@ function ReportActionsView({
const checkIfContentSmallerThanList = useCallback(() => windowHeight - DIFF_BETWEEN_SCREEN_HEIGHT_AND_LIST - SPACER > contentListHeight.current, [windowHeight]);
+ const handleReportActionPagination = useCallback(
+ ({firstReportActionID}: {firstReportActionID: string}) => {
+ // This function is a placeholder as the actual pagination is handled by visibleReportActions
+ if (!hasMoreCached && !hasNewestReportAction) {
+ isFirstLinkedActionRender.current = false;
+ fetchNewerAction(newestReportAction);
+ }
+ if (isFirstLinkedActionRender.current) {
+ isFirstLinkedActionRender.current = false;
+ }
+ setCurrentReportActionID(firstReportActionID);
+ },
+ [fetchNewerAction, hasMoreCached, newestReportAction, hasNewestReportAction],
+ );
+
/**
* Retrieves the next set of report actions for the chat once we are nearing the end of what we are currently
* displaying.
@@ -404,7 +400,7 @@ function ReportActionsView({
!force &&
(!reportActionID ||
!isFocused ||
- isLoadingInitialReportActions ||
+ (isLoadingInitialReportActions && !hasMoreCached) ||
isLoadingNewerReportActions ||
// If there was an error only try again once on initial mount. We should also still load
// more in case we have cached messages.
@@ -448,12 +444,13 @@ function ReportActionsView({
if (!ReportActionsView.initMeasured) {
Performance.markEnd(CONST.TIMING.OPEN_REPORT);
Performance.markEnd(CONST.TIMING.REPORT_INITIAL_RENDER);
- Timing.end(CONST.TIMING.REPORT_INITIAL_RENDER);
ReportActionsView.initMeasured = true;
} else {
Performance.markEnd(CONST.TIMING.SWITCH_REPORT);
}
Timing.end(CONST.TIMING.SWITCH_REPORT, hasCachedActionOnFirstRender ? CONST.TIMING.WARM : CONST.TIMING.COLD);
+ Timing.end(CONST.TIMING.SWITCH_REPORT_THREAD);
+ Timing.end(CONST.TIMING.SWITCH_REPORT_FROM_PREVIEW);
}, [hasCachedActionOnFirstRender]);
// Check if the first report action in the list is the one we're currently linked to
@@ -523,9 +520,6 @@ function arePropsEqual(oldProps: ReportActionsViewProps, newProps: ReportActions
return false;
}
- if (!lodashIsEqual(oldProps.isReadyForCommentLinking, newProps.isReadyForCommentLinking)) {
- return false;
- }
if (!lodashIsEqual(oldProps.reportActions, newProps.reportActions)) {
return false;
}
diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx
index 5b3fe6e5986c..d2ffa97f58b2 100644
--- a/src/pages/home/report/ThreadDivider.tsx
+++ b/src/pages/home/report/ThreadDivider.tsx
@@ -12,7 +12,6 @@ import Navigation from '@libs/Navigation/Navigation';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import type {Ancestor} from '@libs/ReportUtils';
import variables from '@styles/variables';
-import Timing from '@userActions/Timing';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
@@ -48,7 +47,6 @@ function ThreadDivider({ancestor, isLinkDisabled = false}: ThreadDividerProps) {
) : (
{
- Timing.start(CONST.TIMING.SWITCH_REPORT);
const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(ancestor.reportAction, ancestor.reportAction.reportActionID ?? '-1');
// Pop the thread report screen before navigating to the chat report.
Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1'));
diff --git a/src/pages/home/sidebar/AllSettingsScreen.tsx b/src/pages/home/sidebar/AllSettingsScreen.tsx
index b01f3573bcc0..dc969cb98622 100644
--- a/src/pages/home/sidebar/AllSettingsScreen.tsx
+++ b/src/pages/home/sidebar/AllSettingsScreen.tsx
@@ -65,8 +65,8 @@ function AllSettingsScreen({policies}: AllSettingsScreenProps) {
]
: []),
{
- translationKey: 'allSettingsScreen.cardsAndDomains',
- icon: Expensicons.CardsAndDomains,
+ translationKey: 'allSettingsScreen.domains',
+ icon: Expensicons.Globe,
action: () => {
Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL);
},
diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx
index 40818831874b..53f9ae01ec61 100644
--- a/src/pages/iou/request/IOURequestStartPage.tsx
+++ b/src/pages/iou/request/IOURequestStartPage.tsx
@@ -9,6 +9,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import TabSelector from '@components/TabSelector/TabSelector';
import useLocalize from '@hooks/useLocalize';
import usePermissions from '@hooks/usePermissions';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as KeyDownPressListener from '@libs/KeyboardShortcut/KeyDownPressListener';
@@ -40,8 +41,7 @@ function IOURequestStartPage({
const {translate} = useLocalize();
const [isDraggingOver, setIsDraggingOver] = useState(false);
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID || -1}`);
+ const policy = usePolicy(report?.policyID);
const [selectedTab] = useOnyx(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.IOU_REQUEST_TYPE}`);
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${route?.params.transactionID || -1}`);
diff --git a/src/pages/iou/request/step/IOURequestStepCompanyInfo.tsx b/src/pages/iou/request/step/IOURequestStepCompanyInfo.tsx
index b1454b76aca6..53d42b42e908 100644
--- a/src/pages/iou/request/step/IOURequestStepCompanyInfo.tsx
+++ b/src/pages/iou/request/step/IOURequestStepCompanyInfo.tsx
@@ -9,6 +9,7 @@ import TextInput from '@components/TextInput';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import playSound, {SOUNDS} from '@libs/Sound';
@@ -36,7 +37,7 @@ function IOURequestStepCompanyInfo({route, report, transaction}: IOURequestStepC
const {inputCallbackRef} = useAutoFocusInput();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${IOU.getIOURequestPolicyID(transaction, report)}`);
+ const policy = usePolicy(IOU.getIOURequestPolicyID(transaction, report));
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${IOU.getIOURequestPolicyID(transaction, report)}`);
const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${IOU.getIOURequestPolicyID(transaction, report)}`);
diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
index bbdc60153bac..819f1b33f815 100644
--- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
+++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx
@@ -295,7 +295,7 @@ function IOURequestStepConfirmation({
policyTags,
policyCategories,
gpsPoints,
- Object.keys(transaction?.comment?.waypoints ?? {}).length ? TransactionUtils.getValidWaypoints(transaction.comment.waypoints, true) : undefined,
+ Object.keys(transaction?.comment?.waypoints ?? {}).length ? TransactionUtils.getValidWaypoints(transaction.comment?.waypoints, true) : undefined,
action,
transaction.actionableWhisperReportActionID,
transaction.linkedTrackedExpenseReportAction,
@@ -323,7 +323,7 @@ function IOURequestStepConfirmation({
transaction.currency,
transaction.merchant,
transaction.billable,
- TransactionUtils.getValidWaypoints(transaction.comment.waypoints, true),
+ TransactionUtils.getValidWaypoints(transaction.comment?.waypoints, true),
policy,
policyTags,
policyCategories,
@@ -350,7 +350,7 @@ function IOURequestStepConfirmation({
participantsWithAmount.includes(participant.isPolicyExpenseChat ? participant?.ownerAccountID ?? -1 : participant.accountID ?? -1),
);
}
- const trimmedComment = (transaction?.comment.comment ?? '').trim();
+ const trimmedComment = transaction?.comment?.comment?.trim() ?? '';
// Don't let the form be submitted multiple times while the navigator is waiting to take the user to a different page
if (formHasBeenSubmitted.current) {
@@ -533,9 +533,7 @@ function IOURequestStepConfirmation({
const sendMoney = useCallback(
(paymentMethod: PaymentMethodType | undefined) => {
const currency = transaction?.currency;
-
- const trimmedComment = transaction?.comment?.comment ? transaction.comment.comment.trim() : '';
-
+ const trimmedComment = transaction?.comment?.comment?.trim() ?? '';
const participant = participants?.[0];
if (!participant || !transaction?.amount || !currency) {
@@ -611,7 +609,7 @@ function IOURequestStepConfirmation({
transaction={transaction}
selectedParticipants={participants}
iouAmount={Math.abs(transaction?.amount ?? 0)}
- iouComment={transaction?.comment.comment ?? ''}
+ iouComment={transaction?.comment?.comment ?? ''}
iouCurrencyCode={transaction?.currency}
iouIsBillable={transaction?.billable}
onToggleBillable={setBillable}
diff --git a/src/pages/iou/request/step/IOURequestStepDescription.tsx b/src/pages/iou/request/step/IOURequestStepDescription.tsx
index 7505b88d0745..7ed7c8045a81 100644
--- a/src/pages/iou/request/step/IOURequestStepDescription.tsx
+++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx
@@ -75,7 +75,7 @@ function IOURequestStepDescription({
const focusTimeoutRef = useRef(null);
// In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value
const isEditingSplitBill = iouType === CONST.IOU.TYPE.SPLIT && action === CONST.IOU.ACTION.EDIT;
- const currentDescription = isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction?.comment.comment ?? '' : transaction?.comment.comment ?? '';
+ const currentDescription = isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction?.comment?.comment ?? '' : transaction?.comment?.comment ?? '';
useFocusEffect(
useCallback(() => {
focusTimeoutRef.current = setTimeout(() => {
diff --git a/src/pages/iou/request/step/IOURequestStepDistance.tsx b/src/pages/iou/request/step/IOURequestStepDistance.tsx
index 566d5b786c6a..1798a95490a7 100644
--- a/src/pages/iou/request/step/IOURequestStepDistance.tsx
+++ b/src/pages/iou/request/step/IOURequestStepDistance.tsx
@@ -415,7 +415,7 @@ function IOURequestStepDistance({
if (isEditing) {
// If nothing was changed, simply go to transaction thread
// We compare only addresses because numbers are rounded while backup
- const oldWaypoints = transactionBackup?.comment.waypoints ?? {};
+ const oldWaypoints = transactionBackup?.comment?.waypoints ?? {};
const oldAddresses = Object.fromEntries(Object.entries(oldWaypoints).map(([key, waypoint]) => [key, 'address' in waypoint ? waypoint.address : {}]));
const addresses = Object.fromEntries(Object.entries(waypoints).map(([key, waypoint]) => [key, 'address' in waypoint ? waypoint.address : {}]));
const hasRouteChanged = !isEqual(transactionBackup?.routes, transaction?.routes);
diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx
index d3d7e3ba12cd..71c42acefdaa 100644
--- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx
+++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx
@@ -67,7 +67,7 @@ function IOURequestStepWaypoint({
const {isOffline} = useNetwork();
const textInput = useRef(null);
const parsedWaypointIndex = parseInt(pageIndex, 10);
- const allWaypoints = transaction?.comment.waypoints ?? {};
+ const allWaypoints = transaction?.comment?.waypoints ?? {};
const currentWaypoint = allWaypoints[`waypoint${pageIndex}`] ?? {};
const waypointCount = Object.keys(allWaypoints).length;
const filledWaypointCount = Object.values(allWaypoints).filter((waypoint) => !isEmptyObject(waypoint)).length;
diff --git a/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx b/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx
index b523d8102b50..83f5d90b85af 100644
--- a/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx
+++ b/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx
@@ -141,6 +141,7 @@ function ExitSurveyResponsePage({draftResponse, route, navigation}: ExitSurveyRe
}}
containerStyles={[baseResponseInputContainerStyle]}
shouldSaveDraft
+ shouldSubmitForm
/>
>
)}
diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx
index 39e3dc9a8989..bc98a9432630 100755
--- a/src/pages/settings/InitialSettingsPage.tsx
+++ b/src/pages/settings/InitialSettingsPage.tsx
@@ -194,8 +194,8 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa
brickRoadIndicator: hasGlobalWorkspaceSettingsRBR(policies) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
},
{
- translationKey: 'allSettingsScreen.cardsAndDomains',
- icon: Expensicons.CardsAndDomains,
+ translationKey: 'allSettingsScreen.domains',
+ icon: Expensicons.Globe,
action: () => {
Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL);
},
diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx
index 9a02c0fef67e..af0cd242e301 100644
--- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx
+++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx
@@ -2,7 +2,6 @@ import type {StackScreenProps} from '@react-navigation/stack';
import {Str} from 'expensify-common';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {InteractionManager, Keyboard, View} from 'react-native';
-import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import ConfirmModal from '@components/ConfirmModal';
@@ -28,19 +27,11 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
-import type {Policy} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import ValidateCodeForm from './ValidateCodeForm';
import type {ValidateCodeFormHandle} from './ValidateCodeForm/BaseValidateCodeForm';
-const policiesSelector = (policy: OnyxEntry): Pick => ({
- id: policy?.id ?? '-1',
- ownerAccountID: policy?.ownerAccountID,
- owner: policy?.owner ?? '',
- employeeList: policy?.employeeList,
-});
-
type ContactMethodDetailsPageProps = StackScreenProps;
function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) {
@@ -49,9 +40,8 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) {
const [myDomainSecurityGroups, myDomainSecurityGroupsResult] = useOnyx(ONYXKEYS.MY_DOMAIN_SECURITY_GROUPS);
const [securityGroups, securityGroupsResult] = useOnyx(ONYXKEYS.COLLECTION.SECURITY_GROUP);
const [isLoadingReportData, isLoadingReportDataResult] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA, {initialValue: true});
- const [policies, policiesResult] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: policiesSelector});
- const isLoadingOnyxValues = isLoadingOnyxValue(loginListResult, sessionResult, myDomainSecurityGroupsResult, securityGroupsResult, isLoadingReportDataResult, policiesResult);
+ const isLoadingOnyxValues = isLoadingOnyxValue(loginListResult, sessionResult, myDomainSecurityGroupsResult, securityGroupsResult, isLoadingReportDataResult);
const {formatPhoneNumber, translate} = useLocalize();
const theme = useTheme();
@@ -88,8 +78,8 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) {
* Attempt to set this contact method as user's "Default contact method"
*/
const setAsDefault = useCallback(() => {
- User.setContactMethodAsDefault(contactMethod, policies);
- }, [contactMethod, policies]);
+ User.setContactMethodAsDefault(contactMethod);
+ }, [contactMethod]);
/**
* Checks if the user is allowed to change their default contact method. This should only be allowed if:
diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx
index 556d341d049f..e0b7a23d5df3 100644
--- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx
+++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx
@@ -166,8 +166,8 @@ function BaseValidateCodeForm({account = {}, contactMethod, hasMagicCodeBeenSent
}
setFormError({});
- User.validateSecondaryLogin(contactMethod, validateCode);
- }, [validateCode, contactMethod]);
+ User.validateSecondaryLogin(loginList, contactMethod, validateCode);
+ }, [loginList, validateCode, contactMethod]);
return (
<>
diff --git a/src/pages/tasks/NewTaskPage.tsx b/src/pages/tasks/NewTaskPage.tsx
index ceb1670f6cc4..65c732bd36cb 100644
--- a/src/pages/tasks/NewTaskPage.tsx
+++ b/src/pages/tasks/NewTaskPage.tsx
@@ -166,6 +166,7 @@ function NewTaskPage({task, reports, personalDetails}: NewTaskPageProps) {
title={title}
onPress={() => Navigation.navigate(ROUTES.NEW_TASK_TITLE)}
shouldShowRightIcon
+ rightLabel={translate('common.required')}
/>
diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx
index 8ab1dadccb30..d730dde02a67 100644
--- a/src/pages/workspace/WorkspaceMembersPage.tsx
+++ b/src/pages/workspace/WorkspaceMembersPage.tsx
@@ -331,7 +331,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson
}
}
- const isSelected = selectedEmployees.includes(accountID);
+ const isSelected = selectedEmployees.includes(accountID) && canSelectMultiple;
const isOwner = policy?.owner === details.login;
const isAdmin = policyEmployee.role === CONST.POLICY.ROLE.ADMIN;
@@ -384,6 +384,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson
session?.accountID,
translate,
styles.cursorDefault,
+ canSelectMultiple,
]);
const data = useMemo(() => getUsers(), [getUsers]);
diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
index 760155861f2a..de9a3e15dd56 100644
--- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
+++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
@@ -57,29 +57,6 @@ type SectionObject = {
items: Item[];
};
-// TODO: remove when Onyx data is available
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-const mockedCardsList = {
- test1: {
- cardholder: {accountID: 1, lastName: 'Smith', firstName: 'Bob', displayName: 'Bob Smith', avatar: ''},
- name: 'Test 1',
- limit: 1000,
- lastFourPAN: '1234',
- },
- test2: {
- cardholder: {accountID: 2, lastName: 'Miller', firstName: 'Alex', displayName: 'Alex Miller', avatar: ''},
- name: 'Test 2',
- limit: 2000,
- lastFourPAN: '1234',
- },
- test3: {
- cardholder: {accountID: 3, lastName: 'Brown', firstName: 'Kevin', displayName: 'Kevin Brown', avatar: ''},
- name: 'Test 3',
- limit: 3000,
- lastFourPAN: '1234',
- },
-};
-
function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPageProps) {
const styles = useThemeStyles();
const {shouldUseNarrowLayout} = useResponsiveLayout();
@@ -91,13 +68,10 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
!!policy?.connections?.quickbooksOnline?.config?.syncTax ||
!!policy?.connections?.xero?.config?.importTaxRates ||
!!policy?.connections?.netsuite?.options?.config?.syncOptions?.syncTax;
- const policyID = policy?.id ?? '';
+ const policyID = policy?.id;
// @ts-expect-error a new props will be added during feed api implementation
const workspaceAccountID = (policy?.workspaceAccountID as string) ?? '';
const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}${CONST.EXPENSIFY_CARD.BANK}`);
- // Uncomment this line for testing disabled toggle feature - for c+
- // const [cardsList = mockedCardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`);
-
const [isOrganizeWarningModalOpen, setIsOrganizeWarningModalOpen] = useState(false);
const [isIntegrateWarningModalOpen, setIsIntegrateWarningModalOpen] = useState(false);
const [isReportFieldsWarningModalOpen, setIsReportFieldsWarningModalOpen] = useState(false);
@@ -111,7 +85,10 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
isActive: policy?.areDistanceRatesEnabled ?? false,
pendingAction: policy?.pendingFields?.areDistanceRatesEnabled,
action: (isEnabled: boolean) => {
- DistanceRate.enablePolicyDistanceRates(policy?.id ?? '-1', isEnabled);
+ if (!policyID) {
+ return;
+ }
+ DistanceRate.enablePolicyDistanceRates(policyID, isEnabled);
},
},
{
@@ -121,7 +98,10 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
isActive: policy?.areWorkflowsEnabled ?? false,
pendingAction: policy?.pendingFields?.areWorkflowsEnabled,
action: (isEnabled: boolean) => {
- Policy.enablePolicyWorkflows(policy?.id ?? '-1', isEnabled);
+ if (!policyID) {
+ return;
+ }
+ Policy.enablePolicyWorkflows(policyID, isEnabled);
},
},
];
@@ -136,7 +116,10 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
pendingAction: policy?.pendingFields?.areExpensifyCardsEnabled,
disabled: !isEmptyObject(cardsList),
action: (isEnabled: boolean) => {
- Policy.enableExpensifyCard(policy?.id ?? '-1', isEnabled);
+ if (!policyID) {
+ return;
+ }
+ Policy.enableExpensifyCard(policyID, isEnabled);
},
disabledAction: () => {
setIsDisableExpensifyCardWarningModalOpen(true);
@@ -152,7 +135,10 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
isActive: policy?.areInvoicesEnabled ?? false,
pendingAction: policy?.pendingFields?.areInvoicesEnabled,
action: (isEnabled: boolean) => {
- Policy.enablePolicyInvoicing(policy?.id ?? '-1', isEnabled);
+ if (!policyID) {
+ return;
+ }
+ Policy.enablePolicyInvoicing(policyID, isEnabled);
},
},
];
@@ -166,11 +152,14 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
disabled: hasAccountingConnection,
pendingAction: policy?.pendingFields?.areCategoriesEnabled,
action: (isEnabled: boolean) => {
+ if (!policyID) {
+ return;
+ }
if (hasAccountingConnection) {
setIsOrganizeWarningModalOpen(true);
return;
}
- Category.enablePolicyCategories(policy?.id ?? '-1', isEnabled);
+ Category.enablePolicyCategories(policyID, isEnabled);
},
},
{
@@ -181,11 +170,14 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
disabled: hasAccountingConnection,
pendingAction: policy?.pendingFields?.areTagsEnabled,
action: (isEnabled: boolean) => {
+ if (!policyID) {
+ return;
+ }
if (hasAccountingConnection) {
setIsOrganizeWarningModalOpen(true);
return;
}
- Tag.enablePolicyTags(policy?.id ?? '-1', isEnabled);
+ Tag.enablePolicyTags(policyID, isEnabled);
},
},
{
@@ -196,11 +188,14 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
disabled: hasAccountingConnection,
pendingAction: policy?.pendingFields?.tax,
action: (isEnabled: boolean) => {
+ if (!policyID) {
+ return;
+ }
if (hasAccountingConnection) {
setIsOrganizeWarningModalOpen(true);
return;
}
- Policy.enablePolicyTaxes(policy?.id ?? '-1', isEnabled);
+ Policy.enablePolicyTaxes(policyID, isEnabled);
},
},
];
@@ -214,6 +209,9 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
disabled: hasAccountingConnection,
pendingAction: policy?.pendingFields?.areReportFieldsEnabled,
action: (isEnabled: boolean) => {
+ if (!policyID) {
+ return;
+ }
if (hasAccountingConnection) {
setIsOrganizeWarningModalOpen(true);
return;
@@ -242,15 +240,23 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
isActive: isAccountingEnabled,
pendingAction: policy?.pendingFields?.areConnectionsEnabled,
action: (isEnabled: boolean) => {
+ if (!policyID) {
+ return;
+ }
if (hasAccountingConnection) {
setIsIntegrateWarningModalOpen(true);
return;
}
- Policy.enablePolicyConnections(policy?.id ?? '-1', isEnabled);
+ Policy.enablePolicyConnections(policyID, isEnabled);
},
disabled: hasAccountingConnection,
errors: ErrorUtils.getLatestErrorField(policy ?? {}, CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED),
- onCloseError: () => Policy.clearPolicyErrorField(policy?.id ?? '-1', CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED),
+ onCloseError: () => {
+ if (!policyID) {
+ return;
+ }
+ Policy.clearPolicyErrorField(policyID, CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED);
+ },
},
];
@@ -357,6 +363,9 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
{
+ if (!policyID) {
+ return;
+ }
setIsOrganizeWarningModalOpen(false);
Navigation.navigate(ROUTES.POLICY_ACCOUNTING.getRoute(policyID));
}}
@@ -369,6 +378,9 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
{
+ if (!policyID) {
+ return;
+ }
setIsIntegrateWarningModalOpen(false);
Navigation.navigate(ROUTES.POLICY_ACCOUNTING.getRoute(policyID));
}}
@@ -382,6 +394,9 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
title={translate('workspace.reportFields.disableReportFields')}
isVisible={isReportFieldsWarningModalOpen}
onConfirm={() => {
+ if (!policyID) {
+ return;
+ }
setIsReportFieldsWarningModalOpen(false);
Policy.enablePolicyReportFields(policyID, false);
}}
diff --git a/src/pages/workspace/WorkspaceResetBankAccountModal.tsx b/src/pages/workspace/WorkspaceResetBankAccountModal.tsx
index 81f341999200..5856c71d0a43 100644
--- a/src/pages/workspace/WorkspaceResetBankAccountModal.tsx
+++ b/src/pages/workspace/WorkspaceResetBankAccountModal.tsx
@@ -13,9 +13,6 @@ import type * as OnyxTypes from '@src/types/onyx';
type WorkspaceResetBankAccountModalOnyxProps = {
/** Session info for the currently logged in user. */
session: OnyxEntry;
-
- /** The user's data */
- user: OnyxEntry;
};
type WorkspaceResetBankAccountModalProps = WorkspaceResetBankAccountModalOnyxProps & {
@@ -23,7 +20,7 @@ type WorkspaceResetBankAccountModalProps = WorkspaceResetBankAccountModalOnyxPro
reimbursementAccount: OnyxEntry;
};
-function WorkspaceResetBankAccountModal({reimbursementAccount, session, user}: WorkspaceResetBankAccountModalProps) {
+function WorkspaceResetBankAccountModal({reimbursementAccount, session}: WorkspaceResetBankAccountModalProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const achData = reimbursementAccount?.achData;
@@ -49,7 +46,7 @@ function WorkspaceResetBankAccountModal({reimbursementAccount, session, user}: W
}
danger
onCancel={BankAccounts.cancelResetFreePlanBankAccount}
- onConfirm={() => BankAccounts.resetFreePlanBankAccount(bankAccountID, session, achData?.policyID ?? '-1', user)}
+ onConfirm={() => BankAccounts.resetFreePlanBankAccount(bankAccountID, session, achData?.policyID ?? '-1')}
shouldShowCancelButton
isVisible
/>
@@ -62,7 +59,4 @@ export default withOnyx category.previousCategoryName === route.params.categoryName);
diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx
index 0c3f23e29c61..23afa9f48891 100644
--- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx
+++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx
@@ -23,6 +23,7 @@ import TextLink from '@components/TextLink';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -60,7 +61,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
const {environmentURL} = useEnvironment();
const policyId = route.params.policyID ?? '-1';
const backTo = route.params?.backTo;
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyId}`);
+ const policy = usePolicy(policyId);
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyId}`);
const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE);
const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0;
@@ -94,14 +95,14 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
return {
text: value.name,
keyForList: value.name,
- isSelected: !!selectedCategories[value.name],
+ isSelected: !!selectedCategories[value.name] && canSelectMultiple,
isDisabled,
pendingAction: value.pendingAction,
errors: value.errors ?? undefined,
rightElement: ,
};
}),
- [policyCategories, selectedCategories, translate],
+ [policyCategories, selectedCategories, canSelectMultiple, translate],
);
const toggleCategory = useCallback((category: PolicyOption) => {
diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx
index 2eaf8673e29c..277a8bf235eb 100644
--- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx
+++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx
@@ -17,6 +17,7 @@ import SelectionListWithModal from '@components/SelectionListWithModal';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -51,7 +52,7 @@ function PolicyDistanceRatesPage({
const [isWarningModalVisible, setIsWarningModalVisible] = useState(false);
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
const isFocused = useIsFocused();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE);
const canSelectMultiple = shouldUseNarrowLayout ? selectionMode?.isEnabled : true;
@@ -109,7 +110,7 @@ function PolicyDistanceRatesPage({
`common.${customUnit?.attributes?.unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES}`,
)}`,
keyForList: value.customUnitRateID ?? '',
- isSelected: selectedDistanceRates.find((rate) => rate.customUnitRateID === value.customUnitRateID) !== undefined,
+ isSelected: selectedDistanceRates.find((rate) => rate.customUnitRateID === value.customUnitRateID) !== undefined && canSelectMultiple,
isDisabled: value.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
pendingAction:
value.pendingAction ??
@@ -120,7 +121,7 @@ function PolicyDistanceRatesPage({
errors: value.errors ?? undefined,
rightElement: ,
})),
- [customUnit?.attributes?.unit, customUnitRates, selectedDistanceRates, translate, policy?.pendingAction],
+ [customUnit?.attributes?.unit, customUnitRates, selectedDistanceRates, translate, policy?.pendingAction, canSelectMultiple],
);
const addRate = () => {
diff --git a/src/pages/workspace/expensifyCard/EmptyCardView.tsx b/src/pages/workspace/expensifyCard/EmptyCardView.tsx
index ace0b84165d8..f83095444036 100644
--- a/src/pages/workspace/expensifyCard/EmptyCardView.tsx
+++ b/src/pages/workspace/expensifyCard/EmptyCardView.tsx
@@ -5,26 +5,23 @@ import * as Illustrations from '@components/Icon/Illustrations';
import ScrollView from '@components/ScrollView';
import CardRowSkeleton from '@components/Skeletons/CardRowSkeleton';
import Text from '@components/Text';
+import useEmptyViewHeaderHeight from '@hooks/useEmptyViewHeaderHeight';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import colors from '@styles/theme/colors';
import CONST from '@src/CONST';
-const HEADER_HEIGHT = 80;
-const BUTTON_HEIGHT = 40;
-const BUTTON_MARGIN = 12;
-
function EmptyCardView() {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {windowHeight, isSmallScreenWidth} = useWindowDimensions();
- const headerHeight = isSmallScreenWidth ? HEADER_HEIGHT + BUTTON_HEIGHT + BUTTON_MARGIN : HEADER_HEIGHT;
+ const headerHeight = useEmptyViewHeaderHeight(isSmallScreenWidth);
return (
-
+
diff --git a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx
index 59a6b168d0bc..c0566d71f686 100644
--- a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx
+++ b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx
@@ -12,6 +12,7 @@ import Popover from '@components/Popover';
import {PressableWithFeedback} from '@components/Pressable';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -38,7 +39,7 @@ type WorkspaceCardsListLabelProps = {
function WorkspaceCardsListLabel({type, value, style}: WorkspaceCardsListLabelProps) {
const route = useRoute>();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`);
+ const policy = usePolicy(route.params.policyID);
const styles = useThemeStyles();
const {windowWidth} = useWindowDimensions();
const {shouldUseNarrowLayout} = useResponsiveLayout();
diff --git a/src/pages/workspace/expensifyCard/WorkspaceEditCardLimitTypePage.tsx b/src/pages/workspace/expensifyCard/WorkspaceEditCardLimitTypePage.tsx
index 8ceef5fe809e..0ea31da33d92 100644
--- a/src/pages/workspace/expensifyCard/WorkspaceEditCardLimitTypePage.tsx
+++ b/src/pages/workspace/expensifyCard/WorkspaceEditCardLimitTypePage.tsx
@@ -8,6 +8,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import Navigation from '@navigation/Navigation';
@@ -41,7 +42,7 @@ function WorkspaceEditCardLimitTypePage({route}: WorkspaceEditCardLimitTypePageP
const styles = useThemeStyles();
const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${policyID}_${CONST.EXPENSIFY_CARD.BANK}`);
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const card = cardsList?.[cardID] ?? mockedCard;
const areApprovalsConfigured = !isEmptyObject(policy?.approver) && policy?.approvalMode !== CONST.POLICY.APPROVAL_MODE.OPTIONAL;
diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx
index 742a5c2a290e..6cd62a5b6189 100644
--- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx
+++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx
@@ -4,7 +4,6 @@ import React, {useCallback, useMemo} from 'react';
import type {ListRenderItemInfo} from 'react-native';
import {FlatList, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
-import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
@@ -13,6 +12,7 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {PressableWithFeedback} from '@components/Pressable';
import ScreenWrapper from '@components/ScreenWrapper';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import localeCompare from '@libs/LocaleCompare';
@@ -20,7 +20,6 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import Navigation from '@navigation/Navigation';
import type {FullScreenNavigatorParamList} from '@navigation/types';
import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {Card, WorkspaceCardsList} from '@src/types/onyx';
@@ -71,7 +70,7 @@ function WorkspaceExpensifyCardListPage({route}: WorkspaceExpensifyCardListPageP
const styles = useThemeStyles();
const policyID = route.params.policyID;
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const policyCurrency = useMemo(() => policy?.outputCurrency ?? CONST.CURRENCY.USD, [policy]);
diff --git a/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx b/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx
index 5b7aef04f928..e9863074274a 100644
--- a/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx
+++ b/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx
@@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportField from '@libs/actions/Policy/ReportField';
import DateUtils from '@libs/DateUtils';
+import localeCompare from '@libs/LocaleCompare';
import Navigation from '@libs/Navigation/Navigation';
import * as PolicyUtils from '@libs/PolicyUtils';
import type {SettingsNavigatorParamList} from '@navigation/types';
@@ -151,7 +152,7 @@ function CreateReportFieldsPage({
description={translate('workspace.reportFields.listValues')}
shouldShowRightIcon
onPress={() => Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELDS_LIST_VALUES.getRoute(policyID))}
- title={formDraft?.[INPUT_IDS.LIST_VALUES]?.join(', ')}
+ title={formDraft?.[INPUT_IDS.LIST_VALUES]?.sort(localeCompare)?.join(', ')}
numberOfLinesTitle={5}
/>
)}
diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx
index 6aca497dd5ef..0f63ddc3d184 100644
--- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx
+++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx
@@ -92,7 +92,7 @@ function ReportFieldsListValuesPage({
index,
text: value,
keyForList: value,
- isSelected: selectedValues[value],
+ isSelected: selectedValues[value] && canSelectMultiple,
enabled: !disabledListValues[index] ?? true,
pendingAction: reportFieldID ? policy?.fieldList?.[ReportUtils.getReportFieldKey(reportFieldID)]?.pendingAction : null,
rightElement: (
@@ -104,7 +104,7 @@ function ReportFieldsListValuesPage({
}))
.sort((a, b) => localeCompare(a.value, b.value));
return [{data, isDisabled: false}];
- }, [disabledListValues, listValues, policy?.fieldList, reportFieldID, selectedValues, translate]);
+ }, [disabledListValues, listValues, policy?.fieldList, reportFieldID, selectedValues, canSelectMultiple, translate]);
const shouldShowEmptyState = Object.values(listValues ?? {}).length <= 0;
const selectedValuesArray = Object.keys(selectedValues).filter((key) => selectedValues[key]);
diff --git a/src/pages/workspace/reportFields/ReportFieldsSettingsPage.tsx b/src/pages/workspace/reportFields/ReportFieldsSettingsPage.tsx
index 347993b1b96b..cc6460d20641 100644
--- a/src/pages/workspace/reportFields/ReportFieldsSettingsPage.tsx
+++ b/src/pages/workspace/reportFields/ReportFieldsSettingsPage.tsx
@@ -10,6 +10,7 @@ import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import ScreenWrapper from '@components/ScreenWrapper';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
+import localeCompare from '@libs/LocaleCompare';
import Navigation from '@libs/Navigation/Navigation';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
@@ -46,8 +47,8 @@ function ReportFieldsSettingsPage({
const isDateFieldType = reportField.type === CONST.REPORT_FIELD_TYPES.DATE;
const isListFieldType = reportField.type === CONST.REPORT_FIELD_TYPES.LIST;
- const isListFieldEmpty = isListFieldType && reportField.values.length <= 0;
- const listValues = Object.values(policy?.fieldList?.[reportFieldKey]?.values ?? {});
+ const isListFieldEmpty = isListFieldType && reportField.disabledOptions.filter((disabledListValue) => !disabledListValue).length <= 0;
+ const listValues = Object.values(policy?.fieldList?.[reportFieldKey]?.values ?? {})?.sort(localeCompare);
const deleteReportFieldAndHideModal = () => {
ReportField.deleteReportFields(policyID, [reportFieldKey]);
diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx
index 9c77d123514a..25e5303461a4 100644
--- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx
+++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx
@@ -23,6 +23,7 @@ import TextLink from '@components/TextLink';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -62,7 +63,7 @@ function WorkspaceReportFieldsPage({
const {translate} = useLocalize();
const isFocused = useIsFocused();
const {environmentURL} = useEnvironment();
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE);
const filteredPolicyFieldList = useMemo(() => {
if (!policy?.fieldList) {
@@ -109,7 +110,7 @@ function WorkspaceReportFieldsPage({
keyForList: String(reportField.fieldID),
orderWeight: reportField.orderWeight,
pendingAction: reportField.pendingAction,
- isSelected: selectedReportFields.find((selectedReportField) => selectedReportField.name === reportField.name) !== undefined,
+ isSelected: selectedReportFields.find((selectedReportField) => selectedReportField.name === reportField.name) !== undefined && canSelectMultiple,
isDisabled: reportField.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
text: reportField.name,
rightElement: (
@@ -122,7 +123,7 @@ function WorkspaceReportFieldsPage({
isDisabled: false,
},
];
- }, [filteredPolicyFieldList, policy, selectedReportFields, translate]);
+ }, [filteredPolicyFieldList, policy, selectedReportFields, canSelectMultiple, translate]);
const updateSelectedReportFields = (item: ReportFieldForList) => {
const fieldKey = ReportUtils.getReportFieldKey(item.fieldID);
diff --git a/src/pages/workspace/tags/TagSettingsPage.tsx b/src/pages/workspace/tags/TagSettingsPage.tsx
index 2a03c7c8a275..ce57a7269598 100644
--- a/src/pages/workspace/tags/TagSettingsPage.tsx
+++ b/src/pages/workspace/tags/TagSettingsPage.tsx
@@ -1,7 +1,7 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
-import {useOnyx, withOnyx} from 'react-native-onyx';
+import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import ConfirmModal from '@components/ConfirmModal';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
@@ -13,6 +13,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import Switch from '@components/Switch';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ErrorUtils from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
@@ -39,7 +40,7 @@ function TagSettingsPage({route, policyTags, navigation}: TagSettingsPageProps)
const styles = useThemeStyles();
const {translate} = useLocalize();
const policyTag = useMemo(() => PolicyUtils.getTagList(policyTags, route.params.orderWeight), [policyTags, route.params.orderWeight]);
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`);
+ const policy = usePolicy(route.params.policyID);
const [isDeleteTagModalOpen, setIsDeleteTagModalOpen] = React.useState(false);
diff --git a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx
index 1214507480ae..b79863e32245 100644
--- a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx
+++ b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx
@@ -40,7 +40,7 @@ function CreateTagPage({route, policyTags}: CreateTagPageProps) {
const validate = useCallback(
(values: FormOnyxValues) => {
const errors: FormInputErrors = {};
- const tagName = values.tagName.trim();
+ const tagName = PolicyUtils.escapeTagName(values.tagName.trim());
const {tags} = PolicyUtils.getTagList(policyTags, 0);
if (!ValidationUtils.isRequiredFulfilled(tagName)) {
diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx
index ab571377c45b..0fd92614a86e 100644
--- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx
+++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx
@@ -22,6 +22,7 @@ import TextLink from '@components/TextLink';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -52,7 +53,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
const [isDeleteTagsConfirmModalVisible, setIsDeleteTagsConfirmModalVisible] = useState(false);
const isFocused = useIsFocused();
const policyID = route.params.policyID ?? '-1';
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`);
const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE);
const {environmentURL} = useEnvironment();
@@ -92,7 +93,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
orderWeight: policyTagList.orderWeight,
text: PolicyUtils.getCleanedTagName(policyTagList.name),
keyForList: String(policyTagList.orderWeight),
- isSelected: selectedTags[policyTagList.name],
+ isSelected: selectedTags[policyTagList.name] && canSelectMultiple,
pendingAction: getPendingAction(policyTagList),
enabled: true,
required: policyTagList.required,
@@ -109,14 +110,14 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
value: tag.name,
text: PolicyUtils.getCleanedTagName(tag.name),
keyForList: tag.name,
- isSelected: selectedTags[tag.name],
+ isSelected: selectedTags[tag.name] && canSelectMultiple,
pendingAction: tag.pendingAction,
errors: tag.errors ?? undefined,
enabled: tag.enabled,
isDisabled: tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
rightElement: ,
}));
- }, [isMultiLevelTags, policyTagLists, selectedTags, translate]);
+ }, [isMultiLevelTags, policyTagLists, selectedTags, canSelectMultiple, translate]);
const tagListKeyedByName = useMemo(
() =>
diff --git a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx
index 9955d531f856..9da12cb7e948 100644
--- a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx
+++ b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx
@@ -17,6 +17,7 @@ import SelectionListWithModal from '@components/SelectionListWithModal';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
@@ -51,7 +52,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
const [isDeleteTagsConfirmModalVisible, setIsDeleteTagsConfirmModalVisible] = useState(false);
const isFocused = useIsFocused();
const policyID = route.params.policyID ?? '-1';
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`);
const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE);
const currentTagListName = useMemo(() => PolicyUtils.getTagListName(policyTags, route.params.orderWeight), [policyTags, route.params.orderWeight]);
@@ -79,14 +80,14 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
value: tag.name,
text: PolicyUtils.getCleanedTagName(tag.name),
keyForList: tag.name,
- isSelected: selectedTags[tag.name],
+ isSelected: selectedTags[tag.name] && canSelectMultiple,
pendingAction: tag.pendingAction,
errors: tag.errors ?? undefined,
enabled: tag.enabled,
isDisabled: tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
rightElement: ,
})),
- [currentPolicyTag, selectedTags, translate],
+ [currentPolicyTag, selectedTags, canSelectMultiple, translate],
);
const hasDependentTags = useMemo(() => PolicyUtils.hasDependentTags(policy, policyTags), [policy, policyTags]);
diff --git a/src/pages/workspace/taxes/WorkspaceTaxCodePage.tsx b/src/pages/workspace/taxes/WorkspaceTaxCodePage.tsx
index d32961a9d78b..e9005a8a58f2 100644
--- a/src/pages/workspace/taxes/WorkspaceTaxCodePage.tsx
+++ b/src/pages/workspace/taxes/WorkspaceTaxCodePage.tsx
@@ -1,7 +1,6 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useCallback} from 'react';
import {View} from 'react-native';
-import {useOnyx} from 'react-native-onyx';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import type {FormOnyxValues} from '@components/Form/types';
@@ -10,6 +9,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import TextInput from '@components/TextInput';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useLocalize from '@hooks/useLocalize';
+import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import {setPolicyTaxCode, validateTaxCode} from '@libs/actions/TaxRate';
import Navigation from '@libs/Navigation/Navigation';
@@ -29,7 +29,7 @@ function WorkspaceTaxCodePage({route}: WorkspaceTaxCodePageProps) {
const policyID = route.params.policyID ?? '-1';
const currentTaxCode = route.params.taxID;
- const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
+ const policy = usePolicy(policyID);
const {inputCallbackRef} = useAutoFocusInput();
const setTaxCode = useCallback(
diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx
index 95f74d3b3f37..02d807ed63d1 100644
--- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx
+++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx
@@ -111,7 +111,7 @@ function WorkspaceTaxesPage({
text: value.name,
alternateText: textForDefault(key, value),
keyForList: key,
- isSelected: !!selectedTaxesIDs.includes(key),
+ isSelected: !!selectedTaxesIDs.includes(key) && canSelectMultiple,
isDisabledCheckbox: !PolicyUtils.canEditTaxRate(policy, key),
isDisabled: value.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
pendingAction: value.pendingAction ?? (Object.keys(value.pendingFields ?? {}).length > 0 ? CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE : null),
@@ -119,7 +119,7 @@ function WorkspaceTaxesPage({
rightElement: ,
}))
.sort((a, b) => (a.text ?? a.keyForList ?? '').localeCompare(b.text ?? b.keyForList ?? ''));
- }, [policy, textForDefault, selectedTaxesIDs, translate]);
+ }, [policy, textForDefault, selectedTaxesIDs, canSelectMultiple, translate]);
const isLoading = !isOffline && taxesList === undefined;
diff --git a/src/stories/Composer.stories.tsx b/src/stories/Composer.stories.tsx
index a92dc0e789a0..805f2b4c7448 100644
--- a/src/stories/Composer.stories.tsx
+++ b/src/stories/Composer.stories.tsx
@@ -3,7 +3,6 @@ import type {Meta} from '@storybook/react';
import {ExpensiMark} from 'expensify-common';
import React, {useState} from 'react';
import {Image, View} from 'react-native';
-import type {FileObject} from '@components/AttachmentModal';
import Composer from '@components/Composer';
import type {ComposerProps} from '@components/Composer/types';
import RenderHTML from '@components/RenderHTML';
@@ -30,7 +29,7 @@ const parser = new ExpensiMark();
function Default(props: ComposerProps) {
const StyleUtils = useStyleUtils();
- const [pastedFile, setPastedFile] = useState(null);
+ const [pastedFile, setPastedFile] = useState(null);
const [comment, setComment] = useState(props.defaultValue);
const renderedHTML = parser.replace(comment ?? '');
@@ -54,7 +53,7 @@ function Default(props: ComposerProps) {
Rendered Comment
{!!renderedHTML && }
- {!!pastedFile && pastedFile instanceof File && (
+ {!!pastedFile && (
{
expect(transaction?.amount).toBe(amount);
// The comment should be correct
- expect(transaction?.comment.comment).toBe(comment);
+ expect(transaction?.comment?.comment).toBe(comment);
// It should be pending
expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
@@ -363,7 +363,7 @@ describe('actions/IOU', () => {
expect(transaction?.amount).toBe(amount);
// The comment should be correct
- expect(transaction?.comment.comment).toBe(comment);
+ expect(transaction?.comment?.comment).toBe(comment);
expect(transaction?.merchant).toBe(CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT);
@@ -556,7 +556,7 @@ describe('actions/IOU', () => {
expect(newTransaction?.reportID).toBe(iouReportID);
expect(newTransaction?.amount).toBe(amount);
- expect(newTransaction?.comment.comment).toBe(comment);
+ expect(newTransaction?.comment?.comment).toBe(comment);
expect(newTransaction?.merchant).toBe(CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT);
expect(newTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
@@ -713,7 +713,7 @@ describe('actions/IOU', () => {
expect(transaction?.reportID).toBe(iouReportID);
expect(transaction?.amount).toBe(amount);
- expect(transaction?.comment.comment).toBe(comment);
+ expect(transaction?.comment?.comment).toBe(comment);
expect(transaction?.merchant).toBe(CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT);
expect(transaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
@@ -1304,23 +1304,23 @@ describe('actions/IOU', () => {
expect(vitTransaction?.amount).toBe(amount / 4);
expect(groupTransaction?.amount).toBe(amount);
- expect(carlosTransaction?.comment.comment).toBe(comment);
- expect(julesTransaction?.comment.comment).toBe(comment);
- expect(vitTransaction?.comment.comment).toBe(comment);
- expect(groupTransaction?.comment.comment).toBe(comment);
+ expect(carlosTransaction?.comment?.comment).toBe(comment);
+ expect(julesTransaction?.comment?.comment).toBe(comment);
+ expect(vitTransaction?.comment?.comment).toBe(comment);
+ expect(groupTransaction?.comment?.comment).toBe(comment);
expect(carlosTransaction?.merchant).toBe(merchant);
expect(julesTransaction?.merchant).toBe(merchant);
expect(vitTransaction?.merchant).toBe(merchant);
expect(groupTransaction?.merchant).toBe(merchant);
- expect(carlosTransaction?.comment.source).toBe(CONST.IOU.TYPE.SPLIT);
- expect(julesTransaction?.comment.source).toBe(CONST.IOU.TYPE.SPLIT);
- expect(vitTransaction?.comment.source).toBe(CONST.IOU.TYPE.SPLIT);
+ expect(carlosTransaction?.comment?.source).toBe(CONST.IOU.TYPE.SPLIT);
+ expect(julesTransaction?.comment?.source).toBe(CONST.IOU.TYPE.SPLIT);
+ expect(vitTransaction?.comment?.source).toBe(CONST.IOU.TYPE.SPLIT);
- expect(carlosTransaction?.comment.originalTransactionID).toBe(groupTransaction?.transactionID);
- expect(julesTransaction?.comment.originalTransactionID).toBe(groupTransaction?.transactionID);
- expect(vitTransaction?.comment.originalTransactionID).toBe(groupTransaction?.transactionID);
+ expect(carlosTransaction?.comment?.originalTransactionID).toBe(groupTransaction?.transactionID);
+ expect(julesTransaction?.comment?.originalTransactionID).toBe(groupTransaction?.transactionID);
+ expect(vitTransaction?.comment?.originalTransactionID).toBe(groupTransaction?.transactionID);
expect(carlosTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
expect(julesTransaction?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
diff --git a/tests/unit/NextStepUtilsTest.ts b/tests/unit/NextStepUtilsTest.ts
index 24de0d20826c..2b915fcfc4f0 100644
--- a/tests/unit/NextStepUtilsTest.ts
+++ b/tests/unit/NextStepUtilsTest.ts
@@ -74,7 +74,7 @@ describe('libs/NextStepUtils', () => {
test('self review', () => {
optimisticNextStep.icon = CONST.NEXT_STEP.ICONS.HOURGLASS;
- // Waiting for userSubmitter to add expenses.
+ // Waiting for userSubmitter to add expense(s).
optimisticNextStep.message = [
{
text: 'Waiting for ',
@@ -88,10 +88,9 @@ describe('libs/NextStepUtils', () => {
},
{
text: 'add',
- type: 'strong',
},
{
- text: ' expenses.',
+ text: ' %expenses.',
},
];
@@ -114,15 +113,14 @@ describe('libs/NextStepUtils', () => {
text: 'Waiting for ',
},
{
- text: `${currentUserEmail}`,
+ text: `${currentUserEmail}'s`,
type: 'strong',
},
{
- text: "'s %expenses to ",
+ text: ' %expenses to automatically submit',
},
{
- text: 'automatically submit later today',
- type: 'strong',
+ text: ' later today',
},
];
@@ -145,15 +143,14 @@ describe('libs/NextStepUtils', () => {
text: 'Waiting for ',
},
{
- text: `${currentUserEmail}`,
+ text: `${currentUserEmail}'s`,
type: 'strong',
},
{
- text: "'s %expenses to ",
+ text: ' %expenses to automatically submit',
},
{
- text: 'automatically submit on Sunday',
- type: 'strong',
+ text: ' on Sunday',
},
];
@@ -176,15 +173,14 @@ describe('libs/NextStepUtils', () => {
text: 'Waiting for ',
},
{
- text: `${currentUserEmail}`,
+ text: `${currentUserEmail}'s`,
type: 'strong',
},
{
- text: "'s %expenses to ",
+ text: ' %expenses to automatically submit',
},
{
- text: 'automatically submit on the 1st and 16th of each month',
- type: 'strong',
+ text: ' on the 1st and 16th of each month',
},
];
@@ -207,15 +203,14 @@ describe('libs/NextStepUtils', () => {
text: 'Waiting for ',
},
{
- text: `${currentUserEmail}`,
+ text: `${currentUserEmail}'s`,
type: 'strong',
},
{
- text: "'s %expenses to ",
+ text: ' %expenses to automatically submit',
},
{
- text: 'automatically submit on the 2nd of each month',
- type: 'strong',
+ text: ' on the 2nd of each month',
},
];
@@ -239,15 +234,14 @@ describe('libs/NextStepUtils', () => {
text: 'Waiting for ',
},
{
- text: `${currentUserEmail}`,
+ text: `${currentUserEmail}'s`,
type: 'strong',
},
{
- text: "'s %expenses to ",
+ text: ' %expenses to automatically submit',
},
{
- text: `automatically submit on the ${format(lastDayOfMonth(new Date()), CONST.DATE.ORDINAL_DAY_OF_MONTH)} of each month`,
- type: 'strong',
+ text: ` on the ${format(lastDayOfMonth(new Date()), CONST.DATE.ORDINAL_DAY_OF_MONTH)} of each month`,
},
];
@@ -273,15 +267,14 @@ describe('libs/NextStepUtils', () => {
text: 'Waiting for ',
},
{
- text: `${currentUserEmail}`,
+ text: `${currentUserEmail}'s`,
type: 'strong',
},
{
- text: "'s %expenses to ",
+ text: ' %expenses to automatically submit',
},
{
- text: `automatically submit on the ${format(setDate(new Date(), lastBusinessDayOfMonth), CONST.DATE.ORDINAL_DAY_OF_MONTH)} of each month`,
- type: 'strong',
+ text: ` on the ${format(setDate(new Date(), lastBusinessDayOfMonth), CONST.DATE.ORDINAL_DAY_OF_MONTH)} of each month`,
},
];
@@ -305,15 +298,14 @@ describe('libs/NextStepUtils', () => {
text: 'Waiting for ',
},
{
- text: `${currentUserEmail}`,
+ text: `${currentUserEmail}'s`,
type: 'strong',
},
{
- text: "'s %expenses to ",
+ text: ' %expenses to automatically submit',
},
{
- text: `automatically submit at the end of their trip`,
- type: 'strong',
+ text: ` at the end of their trip`,
},
];
@@ -330,7 +322,7 @@ describe('libs/NextStepUtils', () => {
});
test('manual', () => {
- // Waiting for userSubmitter to add expenses.
+ // Waiting for userSubmitter to add expense(s).
optimisticNextStep.message = [
{
text: 'Waiting for ',
@@ -344,10 +336,9 @@ describe('libs/NextStepUtils', () => {
},
{
text: 'add',
- type: 'strong',
},
{
- text: ' expenses.',
+ text: ' %expenses.',
},
];
@@ -383,7 +374,6 @@ describe('libs/NextStepUtils', () => {
},
{
text: 'pay',
- type: 'strong',
},
{
text: ' %expenses.',
@@ -413,7 +403,6 @@ describe('libs/NextStepUtils', () => {
},
{
text: 'approve',
- type: 'strong',
},
{
text: ' %expenses.',
@@ -451,7 +440,6 @@ describe('libs/NextStepUtils', () => {
},
{
text: 'approve',
- type: 'strong',
},
{
text: ' %expenses.',
@@ -475,7 +463,7 @@ describe('libs/NextStepUtils', () => {
optimisticNextStep.icon = CONST.NEXT_STEP.ICONS.CHECKMARK;
optimisticNextStep.message = [
{
- text: 'Finished! No further action required.',
+ text: 'No further action required!',
},
];
@@ -495,7 +483,7 @@ describe('libs/NextStepUtils', () => {
optimisticNextStep.icon = CONST.NEXT_STEP.ICONS.CHECKMARK;
optimisticNextStep.message = [
{
- text: 'Finished! No further action required.',
+ text: 'No further action required!',
},
];
@@ -521,7 +509,6 @@ describe('libs/NextStepUtils', () => {
},
{
text: 'pay',
- type: 'strong',
},
{
text: ' %expenses.',
@@ -547,7 +534,7 @@ describe('libs/NextStepUtils', () => {
optimisticNextStep.icon = CONST.NEXT_STEP.ICONS.CHECKMARK;
optimisticNextStep.message = [
{
- text: 'Finished! No further action required.',
+ text: 'No further action required!',
},
];
diff --git a/tests/unit/markPullRequestsAsDeployedTest.ts b/tests/unit/markPullRequestsAsDeployedTest.ts
index bf90921452ba..4d491db2e53e 100644
--- a/tests/unit/markPullRequestsAsDeployedTest.ts
+++ b/tests/unit/markPullRequestsAsDeployedTest.ts
@@ -3,6 +3,7 @@
/**
* @jest-environment node
*/
+import CONST from '../../.github/libs/CONST';
import type {InternalOctokit} from '../../.github/libs/GithubUtils';
import GithubUtils from '../../.github/libs/GithubUtils';
import GitUtils from '../../.github/libs/GitUtils';
@@ -15,6 +16,7 @@ type PullRequest = {
issue_number: number;
title: string;
merged_by: {login: string};
+ labels: Array<{name: string}>;
};
type PullRequestParams = {
@@ -52,6 +54,7 @@ const PRList: Record = {
merged_by: {
login: 'odin',
},
+ labels: [],
},
2: {
issue_number: 2,
@@ -59,6 +62,7 @@ const PRList: Record = {
merged_by: {
login: 'loki',
},
+ labels: [],
},
};
const version = '42.42.42-42';
@@ -246,6 +250,7 @@ platform | result
merged_by: {
login: 'thor',
},
+ labels: [{name: CONST.LABELS.CP_STAGING}],
},
};
}
@@ -256,7 +261,14 @@ platform | result
});
mockGetCommit.mockImplementation(({commit_sha}: Commit) => {
if (commit_sha === 'xyz') {
- return {data: {message: 'Test PR 3 (cherry picked from commit dagdag)', committer: {name: 'freyja'}}};
+ return {
+ data: {
+ message: `Merge pull request #3 blahblahblah
+(cherry picked from commit dagdag)
+(CP triggered by freyja)`,
+ committer: {name: 'freyja'},
+ },
+ };
}
return mockGetCommitDefaultImplementation({commit_sha});
});
diff --git a/tsconfig.json b/tsconfig.json
index 16497c29b8cb..c0a588f47a64 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -24,6 +24,6 @@
"@userActions/*": ["./src/libs/actions/*"]
}
},
- "include": ["src", "desktop", "web", "website", "docs", "assets", "config", "tests", "jest", "__mocks__", ".github/**/*", ".storybook/**/*", "workflow_tests", "scripts"],
+ "include": ["src", "desktop", "web", "website", "docs", "assets", "config", "tests", "jest", "__mocks__", ".github/**/*", ".storybook/**/*", "scripts"],
"exclude": ["**/node_modules/*", "**/dist/*", ".github/actions/**/index.js", "**/docs/*"]
}
diff --git a/workflow_tests/.eslintrc.js b/workflow_tests/.eslintrc.js
deleted file mode 100644
index 5cd4096bc831..000000000000
--- a/workflow_tests/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-module.exports = {
- rules: {
- '@lwc/lwc/no-async-await': 'off',
- 'no-await-in-loop': 'off',
- 'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'],
- },
-};
diff --git a/workflow_tests/README.md b/workflow_tests/README.md
deleted file mode 100644
index b55e2691d13e..000000000000
--- a/workflow_tests/README.md
+++ /dev/null
@@ -1,422 +0,0 @@
-# Testing GitHub Actions workflows locally
-
-## Components
-The workflow testing framework consists mainly of 3 components:
-- [Jest](https://jestjs.io/) - testing framework, also used for [application tests](https://github.com/Expensify/App/tree/main/tests)
-- [Mock-github](https://github.com/kiegroup/mock-github) - package allowing for creation of local repositories, which can be used to make sure that the workflow tests have access only to these files that they should and that they won't modify the actual repository
-- [Act-js](https://github.com/kiegroup/act-js) - JS wrapper around [Act](https://github.com/nektos/act). Act is a tool that allows to run GitHub Actions workflows locally, and Act-js allows to configure and run Act from JS code, like Jest tests. It also provides additional tools like mocking workflow steps and retrieving the workflow output a JSON, which allows for comparison of the actual output with expected values
-
-## Setup
-- Install dependencies from `package.json` file with `npm install`
-- Make sure you have fulfilled the [prerequisites](https://github.com/nektos/act#necessary-prerequisites-for-running-act) for running `Act`
-- Install `Act` with `brew install act` and follow the documentation on [first Act run](https://github.com/nektos/act#first-act-run)
-- Set the environment variable `ACT_BINARY` to the path to your `Act` executable (`which act` if you're not sure what the path is)
-- You should be ready to run the tests now with `npm run workflow-test`
-- You can pre-generate new mocks/assertions/test files for a given workflow by running `npm run workflow-test:generate `
-
-## Running
-- To run the workflow tests simply use
- - `npm run workflow-test`
- - this will run all the tests sequentially, which can take some time
-- To run a specific test suite you can use
- - `npm run workflow-test -- -i `
- - this will run only the test from that specific test file
-- To run a specific test or subset of tests use
- - `npm run workflow-test -- -t ""`
- - this will run only the tests having `` in their name/description
-- You can combine these like `npm run workflow-test -- -i workflow_tests/preDeploy.test.js -t "single specific test"`
-- You can also use all other options which are normally usable with `jest`
-
-## Limitations
-Not all workflows can always be tested this way, for example:
-- Act and Act-js do not support all the runner types available in GitHub Actions, like `macOS` runners or some specific version of `Ubuntu` runners like `ubuntu-20.04-64core`. In these cases the job will be omitted entirely and cannot be tested
-- Testing more complex workflows in their entirety can be extremely time-consuming and cumbersome. It is often optimal to mock most of the steps with expressions printing the input and output conditions
-- Due to the way `Act` and `Act-js` handle workflow output, not much can be checked in the test. What is available, namely whether the job/step executed or not, whether it was successful or not and what its printed output was, should be enough in most scenarios
-- `Act` does not seem to support the conditions set on event parameters when determining whether to run the workflow or not, namely for a workflow defined with:
-```yaml
-on:
- pull_request:
- types: [opened, edited, reopened]
-```
-running `act pull_request -e event_data.json` with `event_data.json` having `{"action": "opened"}` will execute the workflow (as expected), running for example `act push` will not execute it (as expected), but running `act pull_request -e event_data.json` with `event_data.json` having for example `{"action": "assigned"}` **will still execute the workflow** even though it should only be executed with `action` being `opened`, `edited` or `reopened`. This only applies to running the workflow with `Act`, in the GitHub environment it still works as expected
-
-## File structure
-The testing framework file structure within the repository is as follows:
-- `App/` - main application folder
- - `.github/` - GitHub Actions folder
- - `workflows/` - workflows folder
- - `.yml` - workflow file
- - `...` - other workflow files
- - `...` - other GitHub Actions files
- - `workflow_tests/` - workflow testing folder
- - `jest.config.ts` - `Jest` configuration file
- - `README.md` - this readme file
- - `utils.js` - various utility functions used in multiple tests
- - `.test.js` - test suite file for a GitHub Actions workflow named ``
- - `mocks/` - folder with step mock definitions
- - `Mocks.js` - file with step mock definitions for the `../.test.js` suite, or for the `` workflow
- - `...` - other step mock definition files
- - `assertions/` - folder with output assertions
- - `Assertions.js` - file with output assertions for the `../.test.js` suite, or for the `` workflow
- - `...` - other output assertion files
- - `...` - other test suites
- - `...` - other application files
-
-## Utility helpers
-`utils.js` file provides several helper methods to speed up the tests development and maintenance
-
-### `setUpActParams`
-`setUpActParams` allows for initiating the context in which Act will execute the workflow
-
-Parameters:
-- `act` - instance of previously created `Act` object that will be updated with new params
-- `event` - the name of the event, this can be any event name used by GitHub Actions, like `pull_request`, `push`, `workflow_dispatch`, etc.
-- `event_options` - object with options of the event, allowing for customising it for different scenarios, for example `push` event can be customised for pushing to different branches with options `{head: {ref: ''}}`
-- `secrets` - object with secret values provided, like `{: , ...}`
-- `github_token` - value of the GitHub token, analogous to providing `GITHUB_TOKEN` secret
-
-Returns an updated `Act` object instance
-
-Example:
-```javascript
-let act = new kieActJs.Act(repoPath, workflowPath);
-act = utils.setUpActParams(
- act,
- 'push',
- {head: {ref: 'main'}},
- {OS_BOTIFY_TOKEN: 'dummy_token', GITHUB_ACTOR: 'Dummy Tester', SLACK_WEBHOOK: 'dummy_slack_webhook', LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_s3cr3t_p455word'},
- 'dummy_github_token',
-);
-```
-
-### `createMockStep`
-`createMockStep` allows for creating uniform mock step definitions compatible with `Act-js` and reduces time required, as well as possibility of errors/typos slipping in while developing tests. More complex behaviours have to be mocked manually
-
-Parameters:
-- `name` - name of the step that **must correspond to the `name` in the `.yml` file**, otherwise the step cannot be found
-- `message` - the message to be printed to default output when mock gets executed
-- `job_id` - an optional id of the job that will be printed in `[]` square brackets along the `message`, useful when assessing the output with many steps from many jobs
-- `inputs` - a list of input parameters to be printed, useful when checking if the step had been executed with expected inputs
-- `in_envs` - a list of input environment variables, to be printed, useful when checking if the step had been executed in expected environment
-- `outputs` - an object with values which should be printed by the mock to `$GITHUB_OUTPUT`, useful for setting the step output
-- `out_envs` - an objects with values of environment variables set by the step in `$GITHUB_ENV`, useful for modifying the environment by the mock
-- `isSuccessful` - a boolean value indicating whether the step succeeds or not, exits with status `0` (if successful) or `1` (if not)
-
-Returns an object with step mock definition, ready to be provided to the `Act` object instance
-
-Example:
-```javascript
-let mockStep = utils.createMockStep(
- 'Name of the step from .yml',
- 'Message to be printed',
- 'TEST_JOB',
- ['INPUT_1', 'INPUT_2'],
- ['ENV_1', 'ENV_2'],
- {output_1: true, output_2: 'Some Result'},
- {OUT_ENV: 'ENV_VALUE'},
- false,
-);
-```
-results in
-```javascript
-{
- name: 'Name of the step from .yml',
- mockWith: 'echo [MOCK]'
- + ' [TEST_JOB]'
- + ' Message to be printed'
- + ', INPUT_1="{{ inputs.INPUT_1 }}'
- + ', INPUT_2="{{ inputs.INPUT_2 }}'
- + ', ENV_1="{{ env.ENV_1 }}'
- + ', ENV_1="{{ env.ENV_1 }}'
- + '\necho "output_1=true" >> "$GITHUB_OUTPUT"',
- + '\necho "output_2=Some Result" >> "$GITHUB_OUTPUT"',
- + '\necho "OUT_ENV=ENV_VALUE" >> "$GITHUB_ENV"',
- + '\nexit 1',
-}
-```
-
-### `createStepAssertion`
-`createStepAssertion` allows for creating uniform assertions for output from executed step, compatible with step mocks provided by `createMockStep`
-
-Parameters:
-- `name` - name of the step, **has to correspond to the name from `.yml` file**, and the name in the step mock if applicable
-- `isSuccessful` - boolean value for checking if the step should have exited successfully
-- `expectedOutput` - an output that is expected from the step, compared directly - if provided the subsequent parameters are ignored
-- `jobId` - an optional expected job identifier
-- `message` - expected message printed by the step
-- `inputs` - expected input values provided to the step
-- `envs` - expected input environment variables for the step
-
-Returns an object with step expected output definition ready to be provided to `expect()` matcher
-
-Example:
-```javascript
-utils.createStepAssertion(
- 'Name of the step from .yml',
- false,
- null,
- 'TEST_JOB',
- 'Message to be printed',
- [{key: 'INPUT_1', value: true}, {key: 'INPUT_2', value: 'Some value'}],
- [{key: 'PLAIN_ENV_VAR', value: 'Value'}, {key: 'SECRET_ENV_VAR', value: '***'}],
-)
-```
-results in
-```javascript
-{
- name: 'Name of the step from .yml',
- status: 1,
- output: '[MOCK]'
- + ' [TEST_JOB]'
- + ' Message to be printed'
- + ', INPUT_1=true'
- + ', INPUT_2=Some value'
- + ', PLAIN_ENV_VAR=Value'
- + ', SECRET_ENV_VAR=***',
-}
-```
-
-### `setJobRunners`
-`setJobRunners` overwrites the runner types for given jobs, helpful when the runner type in the workflow is not supported by `Act`
-
-Parameters:
-- `act` - instance of previously created `Act` object
-- `jobs` - object with keys being the IDs of the workflow jobs to be modified and values being the names of runners that should be used for them in the test
-- `workflowPath` - path to the workflow file to be updated, **NOTE**: this will modify the file, use the one from the local test repo, not from `App/.github/workflows`!
-
-Returns an `Act` object instance
-
-Let's say you have a workflow with a job using `macos-12` runner, which is unsupported by `Act` - in this case that job will simply be skipped altogether, not allowing you to test it in any way.
-```yaml
-iOS:
- name: Build and deploy iOS
- needs: validateActor
- if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }}
- runs-on: macos-12
- steps:
-```
-You can use this method to change the runner to something that is supported, like
-```javascript
-act = utils.setJobRunners(
- act,
- {
- iOS: 'ubuntu-latest',
- },
- workflowPath,
-);
-```
-Now the test workflow will look as follows, which will allow you to run the job and do at least limited testing
-```yaml
-iOS:
- name: Build and deploy iOS
- needs: validateActor
- if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }}
- runs-on: ubuntu-latest
- steps:
-```
-
-## Typical test file
-The following is the typical test file content, which will be followed by a detailed breakdown
-```javascript
-const path = require('path');
-const kieActJs = require('@kie/act-js');
-const kieMockGithub = require('@kie/mock-github');
-const utils = require('./utils');
-const assertions = require('./assertions/Assertions');
-const mocks = require('./mocks/Mocks');
-
-let mockGithub;
-const FILES_TO_COPY_INTO_TEST_REPO = [
- {
- src: path.resolve(__dirname, '..', '.github', 'actions'),
- dest: '.github/actions',
- },
- {
- src: path.resolve(__dirname, '..', '.github', 'libs'),
- dest: '.github/libs',
- },
- {
- src: path.resolve(__dirname, '..', '.github', 'scripts'),
- dest: '.github/scripts',
- },
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', '.yml'),
- dest: '.github/workflows/.yml',
- },
-];
-
-beforeEach(async () => {
- mockGithub = new MockGithub({
- repo: {
- testWorkflowsRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
-});
-
-afterEach(async () => {
- await mockGithub.teardown();
-});
-
-describe('test some general behaviour', () => {
- test('something happens - test if expected happened next', async () => {
- // get path to the local test repo
- const repoPath = mockGithub.repo.getPath('testWorkflowsRepo') || '';
-
- // get path to the workflow file under test
- const workflowPath = path.join(repoPath, '.github', 'workflows', '.yml');
-
- // instantiate Act in the context of the test repo and given workflow file
- let act = new kieActJs.Act(repoPath, workflowPath);
-
- // set run parameters
- act = utils.setUpActParams(
- act,
- '',
- {head: {ref: ''}},
- {'': '',
- );
-
- // set up mocks
- const testMockSteps = {
- '': [
- {
- name: '',
- mockWith: '',
- },
- {
- name: '',
- mockWith: '',
- },
- ],
- '': [
- utils.createMockStep('', ''),
- utils.createMockStep('', ''),
- ],
- };
-
- // run an event and get the result
- const result = await act
- .runEvent('', {
- workflowFile: path.join(repoPath, '.github', 'workflows'),
- mockSteps: testMockSteps,
- });
-
- // assert results (some steps can run in parallel to each other so the order is not assured
- // therefore we can check which steps have been executed, but not the set job order
- assertions.assertSomethingHappened(result);
- assertions.assertSomethingDidNotHappen(result, false);
- }, timeout);
-);
-```
-
-### Breakdown
-Define which files should be copied into the test repo. In this case we copy `actions`, `libs`, `scripts` folders in their entirety and just the one workflow file we want to test
-```javascript
-const FILES_TO_COPY_INTO_TEST_REPO = [
- {
- src: path.resolve(__dirname, '..', '.github', 'actions'),
- dest: '.github/actions',
- },
- {
- src: path.resolve(__dirname, '..', '.github', 'libs'),
- dest: '.github/libs',
- },
- {
- src: path.resolve(__dirname, '..', '.github', 'scripts'),
- dest: '.github/scripts',
- },
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', '.yml'),
- dest: '.github/workflows/.yml',
- },
-];
-```
-`beforeEach` gets executed before each test. Here we create the local test repository with the files defined in the `FILES_TO_COPY_INTO_TEST_REPO` variable. `testWorkflowRepo` is the name of the test repo and can be changed to whichever name you choose, just remember to use it later when accessing this repo. _Note that we can't use `beforeAll()` method, because while mocking steps `Act-js` modifies the workflow file copied into the test repo and thus mocking could persist between tests_
-```javascript
-beforeEach(async () => {
- mockGithub = new MockGithub({
- repo: {
- testWorkflowsRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
-});
-```
-Similarly, `afterEach` gets executed after each test. In this case we remove the test repo after the test finishes
-```javascript
-afterEach(async () => {
- await mockGithub.teardown();
-});
-```
-Get path to the local test repo, useful to have it in a variable
-```javascript
-const repoPath = mockGithub.repo.getPath('testWorkflowsRepo') || '';
-```
-Get path to the workflow under test. Note that it's the path **in the test repo**
-```javascript
-const workflowPath = path.join(repoPath, '.github', 'workflows', '.yml');
-```
-Instantiate `Act` object instance. Here we provide the constructor with the path to the test repo (so that `Act` can execute in its context) and the path the workflow file under test (so just the workflow we want to test would be executed)
-```javascript
-let act = new kieActJs.Act(repoPath, workflowPath);
-```
-Set up initial parameters for `Act`. This is where we can set secrets, GitHub token and options for the events (like the name of the branch to which the push has been made, etc.)
-```javascript
-act = utils.setUpActParams(
- act,
- '',
- {head: {ref: ''}},
- {'': '',
-);
-```
-Set up step mocks. Here we configure which steps in the workflow should be mocked, and with what behaviour. This takes form of an object with keys corresponding to the names of the jobs in the workflow, and values being mock definitions for specific steps. The steps can be identified either by `id`, `name`, `uses` or `run`. Step mock can be defined either by hand (``) or with the helper method `utils.createMockStep()` (``). Not mocked steps will be executed normally - **make sure this will not have unexpected consequences**
-```javascript
-const testMockSteps = {
- '': [
- {
- name: '',
- mockWith: '',
- },
- {
- name: '',
- mockWith: '',
- },
- ],
- '': [
- utils.createMockStep('', ''),
- utils.createMockStep('', ''),
- ],
-};
-```
-Most important part - actually running the event with `Act`. This executes the specified `` in the context of the local test repo created before and with the workflow under test set up. `result` stores the output of `Act` execution, which can then be compared to what was expected. Note that the `workflowFile` is actually path to _workflow folder_ and not the file itself - `Act-js` determines the name of the workflow by itself, and tries to find it in the specified `workflowFile` path, so _providing the full path to the file will fail_
-```javascript
-const result = await act
- .runEvent('', {
- workflowFile: path.join(repoPath, '.github', 'workflows'),
- mockSteps: testMockSteps,
- });
-```
-Assert results are as expected. This can, for example, include using `expect()` to check if the steps that should be executed have indeed been executed, steps that shouldn't run have not been executed, compare statuses (which steps succeeded, which failed) and step outputs. Outputs can include additional information, like input values, environmental variables, secrets (although these are usually not accessible and represented by `***`, this can still be useful to check if the value exists or not). Here it's usually done with the helper assertion methods defined in the assertions file. Step assertions can be created manually or with `createStepAssertion()` helper method
-```javascript
-assertions.assertSomethingHappened(result);
-assertions.assertSomethingDidNotHappen(result, false);
-```
-
-## FAQ
-### I'm positive that one of the jobs should run, but it doesn't - why?
-#### Check the runner type (`runs-on`) it may not be set (which `Act` does not like) or it may be set to one of the unsupported types (primarily the `macos-...` runner types). You can always overwrite the runner type with `utils.setJobRunners()` helper method
-### My workflow has many jobs, each with many steps, how do I start testing it without spending hours on setup?
-#### First of all, consider splitting the workflow into several smaller pieces, with the main one acting as coordinator and calling the others. Secondly, you can bootstrap the test with `npm run workflow-test:generate .yml`, which will generate mocks and assertions for you, as well as the stub of the test file
-### After using `workflow-test:generate` the files are incomplete, or they have errors. Why?
-#### Make sure that the workflow file you want to test, has all steps with names, as the bootstrapping script uses step names to locate and mock them - same with assertions. After you've added the `name` properties to steps, remove the previously generated files and run the command again
-### I want to just run the test that I am working on, without all the others - how can I do it?
-#### You can pass parameters to the `npm run workflow-test` command as you would with `jest` or `npm test` - `npm run workflow-test -- -i ` will run just the tests within `testfile`. You can also filter further with `-t `
diff --git a/workflow_tests/assertions/authorChecklistAssertions.ts b/workflow_tests/assertions/authorChecklistAssertions.ts
deleted file mode 100644
index 997eac2d3ea9..000000000000
--- a/workflow_tests/assertions/authorChecklistAssertions.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertChecklistJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'CHECKLIST', 'Checkout'),
- createStepAssertion('authorChecklist.ts', true, null, 'CHECKLIST', 'Running authorChecklist.ts', [{key: 'GITHUB_TOKEN', value: '***'}], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertChecklistJobExecuted};
diff --git a/workflow_tests/assertions/cherryPickAssertions.ts b/workflow_tests/assertions/cherryPickAssertions.ts
deleted file mode 100644
index 8cf5dbd56d54..000000000000
--- a/workflow_tests/assertions/cherryPickAssertions.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertValidateActorJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Check if user is deployer', true, null, 'VALIDATEACTOR', 'Checking if user is a deployer', [], [{key: 'GITHUB_TOKEN', value: '***'}])] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertCreateNewVersionJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Create new version', true, null, 'CREATENEWVERSION', 'Creating new version', [], [])] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertCherryPickJobExecuted(workflowResult: Step[], user = 'Dummy Author', pullRequestNumber = '1234', didExecute = true, hasConflicts = false, isSuccessful = true) {
- const steps = [
- createStepAssertion(
- 'Checkout staging branch',
- true,
- null,
- 'CHERRYPICK',
- 'Checking out staging branch',
- [
- {key: 'ref', value: 'staging'},
- {key: 'token', value: '***'},
- ],
- [],
- ),
- createStepAssertion('Set up git for OSBotify', true, null, 'CHERRYPICK', 'Setting up git for OSBotify', [{key: 'GPG_PASSPHRASE', value: '***'}], []),
- createStepAssertion('Get previous app version', true, null, 'CHERRYPICK', 'Get previous app version', [{key: 'SEMVER_LEVEL', value: 'PATCH'}]),
- createStepAssertion('Fetch history of relevant refs', true, null, 'CHERRYPICK', 'Fetch history of relevant refs'),
- createStepAssertion('Get version bump commit', true, null, 'CHERRYPICK', 'Get version bump commit', [], []),
- createStepAssertion(
- 'Get merge commit for pull request to CP',
- true,
- null,
- 'CHERRYPICK',
- 'Get merge commit for pull request to CP',
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'USER', value: user},
- {key: 'PULL_REQUEST_NUMBER', value: pullRequestNumber},
- ],
- [],
- ),
- createStepAssertion('Cherry-pick the version-bump to staging', true, null, 'CHERRYPICK', 'Cherry-picking the version-bump to staging', [], []),
- createStepAssertion('Cherry-pick the merge commit of target PR', true, null, 'CHERRYPICK', 'Cherry-picking the merge commit of target PR', [], []),
- createStepAssertion('Push changes', true, null, 'CHERRYPICK', 'Pushing changes', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const conflictSteps = [
- createStepAssertion(
- 'Create Pull Request to manually finish CP',
- true,
- null,
- 'CHERRYPICK',
- 'Creating Pull Request to manually finish CP',
- [],
- [{key: 'GITHUB_TOKEN', value: 'os_botify_api_token'}],
- ),
- ] as const;
-
- conflictSteps.forEach((step) => {
- if (didExecute && hasConflicts) {
- expect(workflowResult).toEqual(expect.arrayContaining([step]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([step]));
- }
- });
-
- const failedSteps = [
- createStepAssertion(
- 'Announces a CP failure in the #announce Slack room',
- true,
- null,
- 'CHERRYPICK',
- 'Announcing a CP failure',
- [{key: 'status', value: 'custom'}],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SLACK_WEBHOOK_URL', value: '***'},
- ],
- ),
- ] as const;
-
- failedSteps.forEach((step) => {
- if (didExecute && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([step]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([step]));
- }
- });
-}
-
-export default {assertValidateActorJobExecuted, assertCreateNewVersionJobExecuted, assertCherryPickJobExecuted};
diff --git a/workflow_tests/assertions/claAssertions.ts b/workflow_tests/assertions/claAssertions.ts
deleted file mode 100644
index 401e094923dc..000000000000
--- a/workflow_tests/assertions/claAssertions.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertCLAJobExecuted(workflowResult: Step[], commentBody = '', githubRepository = '', didExecute = true, runAssistant = true) {
- const steps = [
- createStepAssertion(
- 'CLA comment check',
- true,
- null,
- 'CLA',
- 'CLA comment check',
- [
- {key: 'text', value: commentBody},
- {key: 'regex', value: '\\s*I have read the CLA Document and I hereby sign the CLA\\s*'},
- ],
- [],
- ),
- createStepAssertion(
- 'CLA comment re-check',
- true,
- null,
- 'CLA',
- 'CLA comment re-check',
- [
- {key: 'text', value: commentBody},
- {key: 'regex', value: '\\s*recheck\\s*'},
- ],
- [],
- ),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const assistantSteps = [
- createStepAssertion(
- 'CLA Assistant',
- true,
- null,
- 'CLA',
- 'CLA Assistant',
- [
- {key: 'path-to-signatures', value: `${githubRepository}/cla.json`},
- {key: 'path-to-document', value: `https://github.com/${githubRepository}/blob/main/contributingGuides/CLA.md`},
- {key: 'branch', value: 'main'},
- {key: 'remote-organization-name', value: 'Expensify'},
- {key: 'remote-repository-name', value: 'CLA'},
- {key: 'lock-pullrequest-aftermerge', value: false},
- {key: 'allowlist', value: 'OSBotify,snyk-bot'},
- ],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'PERSONAL_ACCESS_TOKEN', value: '***'},
- ],
- ),
- ] as const;
-
- assistantSteps.forEach((step) => {
- if (didExecute && runAssistant) {
- expect(workflowResult).toEqual(expect.arrayContaining([step]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([step]));
- }
- });
-}
-
-// eslint-disable-next-line import/prefer-default-export
-export {assertCLAJobExecuted};
diff --git a/workflow_tests/assertions/createNewVersionAssertions.ts b/workflow_tests/assertions/createNewVersionAssertions.ts
deleted file mode 100644
index 253a44060c76..000000000000
--- a/workflow_tests/assertions/createNewVersionAssertions.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertValidateActorJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Get user permissions', true, null, 'VALIDATEACTOR', 'Get user permissions', [], [{key: 'GITHUB_TOKEN', value: '***'}])] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertCreateNewVersionJobExecuted(workflowResult: Step[], semverLevel = 'BUILD', didExecute = true, isSuccessful = true) {
- const steps = [
- createStepAssertion('Run turnstyle', true, null, 'CREATENEWVERSION', 'Run turnstyle', [{key: 'poll-interval-seconds', value: '10'}], [{key: 'GITHUB_TOKEN', value: '***'}]),
- createStepAssertion(
- 'Check out',
- true,
- null,
- 'CREATENEWVERSION',
- 'Check out',
- [
- {key: 'ref', value: 'main'},
- {key: 'token', value: '***'},
- ],
- [],
- ),
- createStepAssertion('Setup git for OSBotify', true, null, 'CREATENEWVERSION', 'Setup git for OSBotify', [{key: 'GPG_PASSPHRASE', value: '***'}], []),
- createStepAssertion(
- 'Generate version',
- true,
- null,
- 'CREATENEWVERSION',
- 'Generate version',
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SEMVER_LEVEL', value: semverLevel},
- ],
- [],
- ),
- createStepAssertion('Commit new version', true, null, 'CREATENEWVERSION', 'Commit new version', [], []),
- createStepAssertion('Update main branch', true, null, 'CREATENEWVERSION', 'Update main branch', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- if (isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- }
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const failedSteps = [
- createStepAssertion('Announce failed workflow in Slack', true, null, 'CREATENEWVERSION', 'Announce failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}], []),
- ] as const;
-
- failedSteps.forEach((step) => {
- if (didExecute && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([step]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([step]));
- }
- });
-}
-
-export default {assertValidateActorJobExecuted, assertCreateNewVersionJobExecuted};
diff --git a/workflow_tests/assertions/deployAssertions.ts b/workflow_tests/assertions/deployAssertions.ts
deleted file mode 100644
index 7d992aef99da..000000000000
--- a/workflow_tests/assertions/deployAssertions.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertDeployStagingJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout staging branch', true, null, 'DEPLOY_STAGING', 'Checking out staging branch', [
- {key: 'ref', value: 'staging'},
- {key: 'token', value: '***'},
- ]),
- createStepAssertion('Setup git for OSBotify', true, null, 'DEPLOY_STAGING', 'Setting up git for OSBotify', [
- {key: 'GPG_PASSPHRASE', value: '***'},
- {key: 'OS_BOTIFY_APP_ID', value: '***'},
- {key: 'OS_BOTIFY_PRIVATE_KEY', value: '***'},
- ]),
- createStepAssertion('Tag version', true, null, 'DEPLOY_STAGING', 'Tagging new version'),
- createStepAssertion('🚀 Push tags to trigger staging deploy 🚀', true, null, 'DEPLOY_STAGING', 'Pushing tag to trigger staging deploy'),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertDeployProductionJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'DEPLOY_PRODUCTION', 'Checking out', [
- {key: 'ref', value: 'production'},
- {key: 'token', value: '***'},
- ]),
- createStepAssertion('Setup git for OSBotify', true, null, 'DEPLOY_PRODUCTION', 'Setting up git for OSBotify', [
- {key: 'GPG_PASSPHRASE', value: '***'},
- {key: 'OS_BOTIFY_APP_ID', value: '***'},
- {key: 'OS_BOTIFY_PRIVATE_KEY', value: '***'},
- ]),
- createStepAssertion('Get current app version', true, null, 'DEPLOY_PRODUCTION', 'Getting current app version'),
- createStepAssertion(
- '🚀 Create release to trigger production deploy 🚀',
- true,
- null,
- 'DEPLOY_PRODUCTION',
- 'Creating release to trigger production deploy',
- [],
- [{key: 'GITHUB_TOKEN', value: 'os_botify_api_token'}],
- ),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertDeployStagingJobExecuted, assertDeployProductionJobExecuted};
diff --git a/workflow_tests/assertions/deployBlockerAssertions.ts b/workflow_tests/assertions/deployBlockerAssertions.ts
deleted file mode 100644
index 3d031dda5d74..000000000000
--- a/workflow_tests/assertions/deployBlockerAssertions.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertUpdateChecklistJobExecuted(workflowResult: Step[], didExecute = true, isSuccessful = true) {
- const steps = [createStepAssertion('updateChecklist', true, null, 'UPDATECHECKLIST', 'Run updateChecklist')] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- if (isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- }
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertDeployBlockerJobExecuted(workflowResult: Step[], didExecute = true, isSuccessful = true, failsAt = -1) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'DEPLOYBLOCKER', 'Checkout'),
- createStepAssertion(
- 'Give the issue/PR the Hourly, Engineering labels',
- true,
- null,
- 'DEPLOYBLOCKER',
- 'Give the issue/PR the Hourly, Engineering labels',
- [],
- [{key: 'GITHUB_TOKEN', value: '***'}],
- ),
- createStepAssertion('Comment on deploy blocker', true, null, 'DEPLOYBLOCKER', 'Comment on deploy blocker', [], [{key: 'GITHUB_TOKEN', value: '***'}]),
- ] as const;
-
- steps.forEach((expectedStep, i) => {
- if (didExecute) {
- if (failsAt === -1 || i < failsAt) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else if (i === failsAt) {
- steps[i].status = 1;
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const successSteps = [
- createStepAssertion(
- 'Post the issue in the #expensify-open-source slack room',
- true,
- null,
- 'DEPLOYBLOCKER',
- 'Post the issue in the expensify-open-source slack room',
- [{key: 'status', value: 'custom'}],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SLACK_WEBHOOK_URL', value: '***'},
- ],
- ),
- ] as const;
-
- successSteps.forEach((step) => {
- if (didExecute && isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([step]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([step]));
- }
- });
-
- const failedSteps = [
- createStepAssertion('Announce failed workflow in Slack', true, null, 'DEPLOYBLOCKER', 'Announce failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}], []),
- ] as const;
-
- failedSteps.forEach((step) => {
- if (didExecute && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([step]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([step]));
- }
- });
-}
-
-export default {assertUpdateChecklistJobExecuted, assertDeployBlockerJobExecuted};
diff --git a/workflow_tests/assertions/failureNotifierAssertions.ts b/workflow_tests/assertions/failureNotifierAssertions.ts
deleted file mode 100644
index 37be4e872d32..000000000000
--- a/workflow_tests/assertions/failureNotifierAssertions.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertNotifyFailureJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Fetch Workflow Run Jobs', true, null, 'NOTIFYFAILURE', 'Fetch Workflow Run Jobs', [], []),
- createStepAssertion('Process Each Failed Job', true, null, 'NOTIFYFAILURE', 'Process Each Failed Job', [], []),
- ] as const;
-
- for (const expectedStep of steps) {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- }
-}
-
-export default {assertNotifyFailureJobExecuted};
diff --git a/workflow_tests/assertions/finishReleaseCycleAssertions.ts b/workflow_tests/assertions/finishReleaseCycleAssertions.ts
deleted file mode 100644
index 5750200affae..000000000000
--- a/workflow_tests/assertions/finishReleaseCycleAssertions.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertValidateJobExecuted(workflowResult: Step[], issueNumber = '', didExecute = true, isTeamMember = true, hasBlockers = false, isSuccessful = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'VALIDATE', 'Checkout', [
- {key: 'ref', value: 'main'},
- {key: 'token', value: '***'},
- ]),
- createStepAssertion('Setup git for OSBotify', true, null, 'VALIDATE', 'Setup git for OSBotify', [
- {key: 'GPG_PASSPHRASE', value: '***'},
- {key: 'OS_BOTIFY_APP_ID', value: '***'},
- {key: 'OS_BOTIFY_PRIVATE_KEY', value: '***'},
- ]),
- createStepAssertion('Validate actor is deployer', true, null, 'VALIDATE', 'Validating if actor is deployer', [], [{key: 'GITHUB_TOKEN', value: 'os_botify_api_token'}]),
- ];
-
- if (isTeamMember) {
- steps.push(
- createStepAssertion(
- 'Check for any deploy blockers',
- true,
- null,
- 'VALIDATE',
- 'Checking for deploy blockers',
- [
- {key: 'GITHUB_TOKEN', value: 'os_botify_api_token'},
- {key: 'ISSUE_NUMBER', value: issueNumber},
- ],
- [],
- ),
- );
- }
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- // eslint-disable-next-line rulesdir/no-negated-variables
- const notTeamMemberSteps = [
- createStepAssertion(
- 'Reopen and comment on issue (not a team member)',
- true,
- null,
- 'VALIDATE',
- 'Reopening issue - not a team member',
- [
- {key: 'GITHUB_TOKEN', value: 'os_botify_api_token'},
- {key: 'ISSUE_NUMBER', value: issueNumber},
- {key: 'COMMENT', value: 'Sorry, only members of @Expensify/Mobile-Deployers can close deploy checklists.\nReopening!'},
- ],
- [],
- ),
- ] as const;
-
- notTeamMemberSteps.forEach((expectedStep) => {
- if (didExecute && !isTeamMember) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const blockerSteps = [
- createStepAssertion(
- 'Reopen and comment on issue (has blockers)',
- true,
- null,
- 'VALIDATE',
- 'Reopening issue - blockers',
- [
- {key: 'GITHUB_TOKEN', value: 'os_botify_api_token'},
- {key: 'ISSUE_NUMBER', value: issueNumber},
- ],
- [],
- ),
- ] as const;
-
- blockerSteps.forEach((expectedStep) => {
- if (didExecute && hasBlockers) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const failedSteps = [
- createStepAssertion('Announce failed workflow in Slack', true, null, 'VALIDATE', 'Announce failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}], []),
- ] as const;
-
- failedSteps.forEach((expectedStep) => {
- if (didExecute && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertUpdateProductionJobExecuted(workflowResult: Step[], didExecute = true, isSuccessful = true) {
- const steps = [
- createStepAssertion(
- 'Checkout',
- true,
- null,
- 'UPDATEPRODUCTION',
- 'Checkout',
- [
- {key: 'ref', value: 'staging'},
- {key: 'token', value: '***'},
- ],
- [],
- ),
- createStepAssertion('Setup git for OSBotify', true, null, 'UPDATEPRODUCTION', 'Setup git for OSBotify', [{key: 'GPG_PASSPHRASE', value: '***'}], []),
- createStepAssertion('Update production branch', true, null, 'UPDATEPRODUCTION', 'Updating production branch', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const failedSteps = [
- createStepAssertion('Announce failed workflow in Slack', true, null, 'UPDATEPRODUCTION', 'Announce failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}], []),
- ] as const;
-
- failedSteps.forEach((expectedStep) => {
- if (didExecute && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertCreateNewPatchVersionJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Create new version', true, null, 'CREATENEWPATCHVERSION', 'Creating new version', [{key: 'SEMVER_LEVEL', value: 'PATCH'}], [])] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertUpdateStagingJobExecuted(workflowResult: Step[], didExecute = true, isSuccessful = true) {
- const steps = [
- createStepAssertion(
- 'Checkout',
- true,
- null,
- 'UPDATESTAGING',
- 'Checkout',
- [
- {key: 'ref', value: 'main'},
- {key: 'token', value: '***'},
- ],
- [],
- ),
- createStepAssertion('Setup git for OSBotify', true, null, 'UPDATESTAGING', 'Setup git for OSBotify', [{key: 'GPG_PASSPHRASE', value: '***'}], []),
- createStepAssertion('Update staging branch to trigger staging deploy', true, null, 'UPDATESTAGING', 'Updating staging branch', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const failedSteps = [
- createStepAssertion('Announce failed workflow in Slack', true, null, 'UPDATESTAGING', 'Announce failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}], []),
- ] as const;
-
- failedSteps.forEach((expectedStep) => {
- if (didExecute && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertValidateJobExecuted, assertUpdateProductionJobExecuted, assertCreateNewPatchVersionJobExecuted, assertUpdateStagingJobExecuted};
diff --git a/workflow_tests/assertions/lintAssertions.ts b/workflow_tests/assertions/lintAssertions.ts
deleted file mode 100644
index 488ec31df95f..000000000000
--- a/workflow_tests/assertions/lintAssertions.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertLintJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'LINT', 'Checkout', [], []),
- createStepAssertion('Setup Node', true, null, 'LINT', 'Setup Node', [], []),
- createStepAssertion('Lint JavaScript and Typescript with ESLint', true, null, 'LINT', 'Lint JavaScript with ESLint', [], [{key: 'CI', value: 'true'}]),
- createStepAssertion("Verify there's no Prettier diff", true, null, 'LINT', 'Verify theres no Prettier diff', [], []),
- createStepAssertion('Run unused style searcher', true, null, 'LINT', 'Run unused style searcher', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertLintJobExecuted};
diff --git a/workflow_tests/assertions/lockDeploysAssertions.ts b/workflow_tests/assertions/lockDeploysAssertions.ts
deleted file mode 100644
index 467e20bc5047..000000000000
--- a/workflow_tests/assertions/lockDeploysAssertions.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertlockStagingDeploysJobExecuted(workflowResult: Step[], didExecute = true, isSuccessful = true) {
- const steps = [
- createStepAssertion(
- 'Checkout',
- true,
- null,
- 'LOCKSTAGINGDEPLOYS',
- 'Checking out',
- [
- {key: 'ref', value: 'main'},
- {key: 'token', value: '***'},
- ],
- [],
- ),
- createStepAssertion('Wait for staging deploys to finish', true, null, 'LOCKSTAGINGDEPLOYS', 'Waiting for staging deploys to finish', [{key: 'GITHUB_TOKEN', value: '***'}], []),
- createStepAssertion(
- 'Comment in StagingDeployCash to give Applause the 🟢 to begin QA',
- true,
- null,
- 'LOCKSTAGINGDEPLOYS',
- 'Commenting in StagingDeployCash',
- [],
- [{key: 'GITHUB_TOKEN', value: '***'}],
- ),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const failProdSteps = [
- createStepAssertion('Announce failed workflow', true, null, 'LOCKSTAGINGDEPLOYS', 'Announcing failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}], []),
- ] as const;
-
- failProdSteps.forEach((expectedStep) => {
- if (didExecute && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertlockStagingDeploysJobFailedAfterFirstStep(workflowResult: Step[]) {
- const steps = [
- createStepAssertion(
- 'Checkout',
- true,
- null,
- 'LOCKSTAGINGDEPLOYS',
- 'Checking out',
- [
- {key: 'ref', value: 'main'},
- {key: 'token', value: '***'},
- ],
- [],
- ),
- createStepAssertion('Wait for staging deploys to finish', false, null, 'LOCKSTAGINGDEPLOYS', 'Waiting for staging deploys to finish', [{key: 'GITHUB_TOKEN', value: '***'}], []),
- createStepAssertion('Announce failed workflow', true, null, 'LOCKSTAGINGDEPLOYS', 'Announcing failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- });
-}
-
-export default {assertlockStagingDeploysJobExecuted, assertlockStagingDeploysJobFailedAfterFirstStep};
diff --git a/workflow_tests/assertions/platformDeployAssertions.ts b/workflow_tests/assertions/platformDeployAssertions.ts
deleted file mode 100644
index af42c6818b47..000000000000
--- a/workflow_tests/assertions/platformDeployAssertions.ts
+++ /dev/null
@@ -1,379 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertVerifyActorJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Check if user is deployer', true, null, 'VALIDATE_ACTOR', 'Checking if the user is a deployer', [], [{key: 'GITHUB_TOKEN', value: '***'}])] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertDeployChecklistJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('deployChecklist', true, null, 'DEPLOY_CHECKLIST', 'Run deployChecklist')] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertAndroidJobExecuted(workflowResult: Step[], didExecute = true, isProduction = true, isSuccessful = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'ANDROID', 'Checking out'),
- createStepAssertion('Configure MapBox SDK', true, null, 'ANDROID', 'Configure MapBox SDK'),
- createStepAssertion('Setup Node', true, null, 'ANDROID', 'Setting up Node'),
- createStepAssertion(
- 'Setup Java',
- true,
- null,
- 'ANDROID',
- 'Setup Java',
- [
- {key: 'distribution', value: 'oracle'},
- {key: 'java-version', value: '17'},
- ],
- [],
- ),
- createStepAssertion('Setup Ruby', true, null, 'ANDROID', 'Setting up Ruby', [
- {key: 'ruby-version', value: '2.7'},
- {key: 'bundler-cache', value: 'true'},
- ]),
- createStepAssertion('Decrypt keystore', true, null, 'ANDROID', 'Decrypting keystore', null, [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Decrypt json key', true, null, 'ANDROID', 'Decrypting JSON key', null, [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Set version in ENV', true, null, 'ANDROID', 'Setting version in ENV'),
- createStepAssertion('Run Fastlane', true, null, 'ANDROID', 'Running Fastlane', null, [
- {key: 'RUBYOPT', value: '-rostruct'},
- {key: 'MYAPP_UPLOAD_STORE_PASSWORD', value: '***'},
- {key: 'MYAPP_UPLOAD_KEY_PASSWORD', value: '***'},
- {key: 'VERSION', value: '1.2.3'},
- ]),
- createStepAssertion('Archive Android sourcemaps', true, null, 'ANDROID', 'Archiving Android sourcemaps', [
- // Note 1.2.3 comes from the ref name that we are on, which is the version we are deploying
- {key: 'name', value: 'android-sourcemap-1.2.3'},
- {key: 'path', value: 'android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map'},
- ]),
- ];
-
- if (isProduction) {
- steps.push(
- createStepAssertion('Upload Android build to GitHub Release', true, null, 'ANDROID', 'Uploading Android build to GitHub Release', null, [{key: 'GITHUB_TOKEN', value: '***'}]),
- );
- } else {
- steps.push(
- createStepAssertion('Upload Android build to GitHub artifacts', true, null, 'ANDROID', 'Uploading Android build to GitHub artifacts', [
- {key: 'name', value: 'app-production-release.aab'},
- {key: 'path', value: 'android/app/build/outputs/bundle/productionRelease/app-production-release.aab'},
- ]),
- createStepAssertion('Upload Android build to Browser Stack', true, null, 'ANDROID', 'Uploading Android build to Browser Stack', null, [{key: 'BROWSERSTACK', value: '***'}]),
- );
- }
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const failProdSteps = [
- createStepAssertion(
- 'Warn deployers if Android production deploy failed',
- true,
- null,
- 'ANDROID',
- 'Warning deployers of failed production deploy',
- [{key: 'status', value: 'custom'}],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SLACK_WEBHOOK_URL', value: '***'},
- ],
- ),
- ] as const;
-
- failProdSteps.forEach((expectedStep) => {
- if (didExecute && isProduction && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertDesktopJobExecuted(workflowResult: Step[], didExecute = true, isProduction = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'DESKTOP', 'Checking out'),
- createStepAssertion('Setup Node', true, null, 'DESKTOP', 'Setting up Node'),
- createStepAssertion('Decrypt Developer ID Certificate', true, null, 'DESKTOP', 'Decrypting developer id certificate', null, [{key: 'DEVELOPER_ID_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Build desktop app', true, null, 'DESKTOP', 'Building desktop app', null, [
- {key: 'CSC_LINK', value: '***'},
- {key: 'CSC_KEY_PASSWORD', value: '***'},
- {key: 'APPLE_ID', value: '***'},
- {key: 'APPLE_APP_SPECIFIC_PASSWORD', value: '***'},
- {key: 'AWS_ACCESS_KEY_ID', value: '***'},
- {key: 'AWS_SECRET_ACCESS_KEY', value: '***'},
- ]),
- createStepAssertion('Upload desktop build to GitHub Workflow', true, null, 'DESKTOP', 'Uploading desktop build to GitHub Workflow', [
- {key: 'name', value: 'NewExpensify.dmg'},
- {key: 'path', value: 'desktop-build/NewExpensify.dmg'},
- ]),
- ];
-
- if (isProduction) {
- steps.push(
- createStepAssertion('Upload desktop build to GitHub Release', true, null, 'DESKTOP', 'Uploading desktop build to GitHub Release', null, [{key: 'GITHUB_TOKEN', value: '***'}]),
- );
- }
-
- steps.push(
- createStepAssertion('Archive desktop sourcemaps', true, null, 'DESKTOP', 'Archiving desktop sourcemaps', [
- // Note 1.2.3 comes from the ref name that we are on, which is the version we are deploying
- {key: 'name', value: 'desktop-sourcemap-1.2.3'},
- {key: 'path', value: 'desktop/dist/www/merged-source-map.js.map'},
- ]),
- );
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertIOSJobExecuted(workflowResult: Step[], didExecute = true, isProduction = true, isSuccessful = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'IOS', 'Checking out'),
- createStepAssertion('Configure MapBox SDK', true, null, 'IOS', 'Configure MapBox SDK'),
- createStepAssertion('Setup Node', true, null, 'IOS', 'Setting up Node'),
- createStepAssertion('Setup Ruby', true, null, 'IOS', 'Setting up Ruby', [
- {key: 'ruby-version', value: '2.7'},
- {key: 'bundler-cache', value: 'true'},
- ]),
- createStepAssertion('Cache Pod dependencies', true, null, 'IOS', 'Cache Pod dependencies', [
- {key: 'path', value: 'ios/Pods'},
- {key: 'key', value: 'Linux-pods-cache-'},
- ]),
- createStepAssertion('Compare Podfile.lock and Manifest.lock', true, null, 'IOS', 'Compare Podfile.lock and Manifest.lock'),
- createStepAssertion('Install cocoapods', true, null, 'IOS', 'Installing cocoapods', [
- {key: 'timeout_minutes', value: '10'},
- {key: 'max_attempts', value: '5'},
- {key: 'command', value: 'cd ios && bundle exec pod install'},
- ]),
- createStepAssertion('Decrypt AppStore profile', true, null, 'IOS', 'Decrypting profile', null, [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Decrypt AppStore Notification Service profile', true, null, 'IOS', 'Decrypting profile', null, [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Decrypt certificate', true, null, 'IOS', 'Decrypting certificate', null, [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Decrypt App Store Connect API key', true, null, 'IOS', 'Decrypting App Store API key', null, [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Set iOS version in ENV', true, null, 'IOS', 'Setting iOS version'),
- createStepAssertion('Run Fastlane', true, null, 'IOS', 'Running Fastlane', null, [
- {key: 'APPLE_CONTACT_EMAIL', value: '***'},
- {key: 'APPLE_CONTACT_PHONE', value: '***'},
- {key: 'APPLE_DEMO_EMAIL', value: '***'},
- {key: 'APPLE_DEMO_PASSWORD', value: '***'},
- {key: 'VERSION', value: '1.2.3'},
- ]),
- createStepAssertion('Archive iOS sourcemaps', true, null, 'IOS', 'Archiving sourcemaps', [
- // Note 1.2.3 comes from the ref name that we are on, which is the version we are deploying
- {key: 'name', value: 'ios-sourcemap-1.2.3'},
- {key: 'path', value: 'main.jsbundle.map'},
- ]),
- ];
-
- if (isProduction) {
- steps.push(createStepAssertion('Upload iOS build to GitHub Release', true, null, 'IOS', 'Uploading iOS build to GitHub Release', null, [{key: 'GITHUB_TOKEN', value: '***'}]));
- } else {
- steps.push(
- createStepAssertion('Upload iOS build to GitHub artifacts', true, null, 'IOS', 'Uploading iOS build to GitHub artifacts', [
- {key: 'name', value: 'New Expensify.ipa'},
- {key: 'path', value: '/Users/runner/work/App/App/New Expensify.ipa'},
- ]),
- createStepAssertion('Upload iOS build to Browser Stack', true, null, 'IOS', 'Uploading build to Browser Stack', null, [{key: 'BROWSERSTACK', value: '***'}]),
- );
- }
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-
- const failProdSteps = [
- createStepAssertion(
- 'Warn deployers if iOS production deploy failed',
- true,
- null,
- 'IOS',
- 'Warning developers of failed deploy',
- [{key: 'status', value: 'custom'}],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SLACK_WEBHOOK_URL', value: '***'},
- ],
- ),
- ] as const;
-
- failProdSteps.forEach((expectedStep) => {
- if (didExecute && isProduction && !isSuccessful) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertWebJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'WEB', 'Checking out'),
- createStepAssertion('Setup Node', true, null, 'WEB', 'Setting up Node'),
- createStepAssertion('Setup Cloudflare CLI', true, null, 'WEB', 'Setting up Cloudflare CLI'),
- createStepAssertion('Configure AWS Credentials', true, null, 'WEB', 'Configuring AWS credentials', [
- {key: 'aws-access-key-id', value: '***'},
- {key: 'aws-secret-access-key', value: '***'},
- {key: 'aws-region', value: 'us-east-1'},
- ]),
- ];
-
- steps.push(
- createStepAssertion('Build web', true, null, 'WEB', 'Building web'),
- createStepAssertion('Build storybook docs', true, null, 'WEB', 'Build storybook docs'),
- createStepAssertion('Deploy to S3', true, null, 'WEB', 'Deploying to S3'),
- createStepAssertion('Archive web sourcemaps', true, null, 'WEB', 'Archiving web sourcemaps', null, [
- // Note 1.2.3 comes from the ref name that we are on, which is the version we are deploying
- {key: 'name', value: 'web-sourcemap-1.2.3'},
- {key: 'path', value: 'dist/merged-source-map.js.map'},
- ]),
- createStepAssertion('Purge Cloudflare cache', true, null, 'WEB', 'Purging Cloudflare cache', null, [{key: 'CF_API_KEY', value: '***'}]),
- );
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertPostSlackOnFailureJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Post Slack message on failure', true, null, 'POST_SLACK_FAIL', 'Posting Slack message on platform deploy failure', [{key: 'SLACK_WEBHOOK', value: '***'}]),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertPostSlackOnSuccessJobExecuted(workflowResult: Step[], didExecute = true, isProduction = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'POST_SLACK_SUCCESS', 'Checking out'),
- createStepAssertion('Set version', true, null, 'POST_SLACK_SUCCESS', 'Setting version'),
- createStepAssertion(
- 'Announces the deploy in the #announce Slack room',
- true,
- null,
- 'POST_SLACK_SUCCESS',
- 'Posting message to #announce channel',
- [{key: 'status', value: 'custom'}],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SLACK_WEBHOOK_URL', value: '***'},
- ],
- ),
- createStepAssertion(
- 'Announces the deploy in the #deployer Slack room',
- true,
- null,
- 'POST_SLACK_SUCCESS',
- 'Posting message to #deployer channel',
- [{key: 'status', value: 'custom'}],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SLACK_WEBHOOK_URL', value: '***'},
- ],
- ),
- ];
-
- if (isProduction) {
- steps.push(
- createStepAssertion(
- 'Announces the deploy in the #expensify-open-source Slack room',
- true,
- null,
- 'POST_SLACK_SUCCESS',
- 'Posting message to #expensify-open-source channel',
- [{key: 'status', value: 'custom'}],
- [
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'SLACK_WEBHOOK_URL', value: '***'},
- ],
- ),
- );
- }
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertPostGithubCommentJobExecuted(workflowResult: Step[], didExecute = true, isProduction = true, didDeploy = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'POST_GITHUB_COMMENT', 'Checking out'),
- createStepAssertion('Setup Node', true, null, 'POST_GITHUB_COMMENT', 'Setting up Node'),
- createStepAssertion('Set version', true, null, 'POST_GITHUB_COMMENT', 'Setting version'),
- createStepAssertion('Get Release Pull Request List', true, null, 'POST_GITHUB_COMMENT', 'Getting release pull request list', [
- {key: 'TAG', value: '1.2.3'},
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'IS_PRODUCTION_DEPLOY', value: isProduction ? 'true' : 'false'},
- ]),
- createStepAssertion('Comment on issues', true, null, 'POST_GITHUB_COMMENT', 'Commenting on issues', [
- {key: 'PR_LIST', value: '[1.2.1, 1.2.2]'},
- {key: 'IS_PRODUCTION_DEPLOY', value: isProduction ? 'true' : 'false'},
- {key: 'DEPLOY_VERSION', value: '1.2.3'},
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'ANDROID', value: didDeploy ? 'success' : 'skipped'},
- {key: 'DESKTOP', value: didDeploy ? 'success' : 'skipped'},
- {key: 'IOS', value: didDeploy ? 'success' : 'skipped'},
- {key: 'WEB', value: didDeploy ? 'success' : 'skipped'},
- ]),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {
- assertVerifyActorJobExecuted,
- assertDeployChecklistJobExecuted,
- assertAndroidJobExecuted,
- assertDesktopJobExecuted,
- assertIOSJobExecuted,
- assertWebJobExecuted,
- assertPostSlackOnFailureJobExecuted,
- assertPostSlackOnSuccessJobExecuted,
- assertPostGithubCommentJobExecuted,
-};
diff --git a/workflow_tests/assertions/preDeployAssertions.ts b/workflow_tests/assertions/preDeployAssertions.ts
deleted file mode 100644
index a2762bc3123c..000000000000
--- a/workflow_tests/assertions/preDeployAssertions.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertTypecheckJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Run typecheck workflow', true, null, 'TYPECHECK', 'Running typecheck workflow')] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertLintJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Run lint workflow', true, null, 'LINT', 'Running lint workflow')] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertTestJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Run test workflow', true, null, 'TEST', 'Running test workflow')] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertChooseDeployActionsJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Get merged pull request', true, null, 'CHOOSE_DEPLOY_ACTIONS', 'Getting merged pull request', [{key: 'github_token', value: '***'}]),
- createStepAssertion('Check if StagingDeployCash is locked', true, null, 'CHOOSE_DEPLOY_ACTIONS', 'Checking StagingDeployCash', [{key: 'GITHUB_TOKEN', value: '***'}]),
- createStepAssertion('Check if merged pull request should trigger a deploy', true, ''),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertSkipDeployJobExecuted(workflowResult: Step[], didExecute = true) {
- const body = ':hand: This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.';
- const steps = [
- createStepAssertion('Comment on deferred PR', true, null, 'SKIP_DEPLOY', 'Skipping deploy', [
- {key: 'github_token', value: '***'},
- {key: 'number', value: '123'},
- {key: 'body', value: body},
- ]),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertCreateNewVersionJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Create new version', true, null, 'CREATE_NEW_VERSION', 'Creating new version')] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertUpdateStagingJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Run turnstyle', true, null, 'UPDATE_STAGING', 'Running turnstyle', [
- {key: 'poll-interval-seconds', value: '10'},
- {key: 'GITHUB_TOKEN', value: '***'},
- ]),
- createStepAssertion('Checkout main', true, null, 'UPDATE_STAGING', 'Checkout main', [
- {key: 'ref', value: 'main'},
- {key: 'token', value: '***'},
- ]),
- createStepAssertion('Setup Git for OSBotify', true, null, 'UPDATE_STAGING', 'Setup Git for OSBotify', [{key: 'GPG_PASSPHRASE', value: '***'}]),
- createStepAssertion('Update staging branch from main', true, null, 'UPDATE_STAGING', 'Update staging branch from main'),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertUpdateStagingJobFailed(workflowResult: Step[], didFail = false) {
- const steps = [
- createStepAssertion('Announce failed workflow in Slack', true, null, 'UPDATE_STAGING', 'Announcing failed workflow in Slack', [{key: 'SLACK_WEBHOOK', value: '***'}]),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didFail) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {
- assertTypecheckJobExecuted,
- assertLintJobExecuted,
- assertTestJobExecuted,
- assertChooseDeployActionsJobExecuted,
- assertSkipDeployJobExecuted,
- assertCreateNewVersionJobExecuted,
- assertUpdateStagingJobExecuted,
- assertUpdateStagingJobFailed,
-};
diff --git a/workflow_tests/assertions/reviewerChecklistAssertions.ts b/workflow_tests/assertions/reviewerChecklistAssertions.ts
deleted file mode 100644
index 4be8e1807dc7..000000000000
--- a/workflow_tests/assertions/reviewerChecklistAssertions.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertChecklistJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('reviewerChecklist.js', true, null, 'CHECKLIST', 'reviewerChecklist.js', [{key: 'GITHUB_TOKEN', value: '***'}], [])] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertChecklistJobExecuted};
diff --git a/workflow_tests/assertions/testAssertions.ts b/workflow_tests/assertions/testAssertions.ts
deleted file mode 100644
index 90fc624a76be..000000000000
--- a/workflow_tests/assertions/testAssertions.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertJestJobExecuted(workflowResult: Step[], didExecute = true, timesExecuted = 3) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'JEST', 'Checkout', [], []),
- createStepAssertion('Setup Node', true, null, 'JEST', 'Setup Node', [], []),
- createStepAssertion('Get number of CPU cores', true, null, 'JEST', 'Get number of CPU cores', [], []),
- createStepAssertion(
- 'Cache Jest cache',
- true,
- null,
- 'JEST',
- 'Cache Jest cache',
- [
- {key: 'path', value: '.jest-cache'},
- {key: 'key', value: 'Linux-jest'},
- ],
- [],
- ),
- createStepAssertion('Jest tests', true, null, 'JEST', 'Jest tests', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- let cnt = 0;
- workflowResult.forEach((executedStep) => {
- if (executedStep.name !== expectedStep.name || executedStep.output !== expectedStep.output || executedStep.status !== expectedStep.status) {
- return;
- }
- cnt += 1;
- });
- expect(cnt).toEqual(timesExecuted);
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertJestJobExecuted};
diff --git a/workflow_tests/assertions/testBuildAssertions.ts b/workflow_tests/assertions/testBuildAssertions.ts
deleted file mode 100644
index 8e1ba1a439d5..000000000000
--- a/workflow_tests/assertions/testBuildAssertions.ts
+++ /dev/null
@@ -1,407 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertValidateActorJobExecuted(workflowResult: Step[], pullRequestNumber = '1234', didExecute = true) {
- const steps = [
- createStepAssertion('Is Expensify employee', true, null, 'VALIDATEACTOR', 'Is Expensify employee', [], [{key: 'GITHUB_TOKEN', value: '***'}]),
- createStepAssertion(
- 'Set HAS_READY_TO_BUILD_LABEL flag',
- true,
- null,
- 'VALIDATEACTOR',
- 'Set HAS_READY_TO_BUILD_LABEL flag',
- [],
- [
- {key: 'PULL_REQUEST_NUMBER', value: pullRequestNumber},
- {key: 'GITHUB_TOKEN', value: '***'},
- ],
- ),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertGetBranchRefJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'GETBRANCHREF', 'Checkout', [], []),
- createStepAssertion('Check if pull request number is correct', true, null, 'GETBRANCHREF', 'Check if pull request number is correct', [], [{key: 'GITHUB_TOKEN', value: '***'}]),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertAndroidJobExecuted(workflowResult: Step[], ref = '', didExecute = true, failsAt = -1) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'ANDROID', 'Checkout', [{key: 'ref', value: ref}], []),
- createStepAssertion('Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it', true, null, 'ANDROID', 'Creating .env.adhoc file based on staging', [], []),
- createStepAssertion('Setup Node', true, null, 'ANDROID', 'Setup Node', [], []),
- createStepAssertion(
- 'Setup Java',
- true,
- null,
- 'ANDROID',
- 'Setup Java',
- [
- {key: 'distribution', value: 'oracle'},
- {key: 'java-version', value: '17'},
- ],
- [],
- ),
- createStepAssertion(
- 'Setup Ruby',
- true,
- null,
- 'ANDROID',
- 'Setup Ruby',
- [
- {key: 'ruby-version', value: '2.7'},
- {key: 'bundler-cache', value: true},
- ],
- [],
- ),
- createStepAssertion('Decrypt keystore', true, null, 'ANDROID', 'Decrypt keystore', [], [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion('Decrypt json key', true, null, 'ANDROID', 'Decrypt json key', [], [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion(
- 'Configure AWS Credentials',
- true,
- null,
- 'ANDROID',
- 'Configure AWS Credentials',
- [
- {key: 'aws-access-key-id', value: '***'},
- {key: 'aws-secret-access-key', value: '***'},
- {key: 'aws-region', value: 'us-east-1'},
- ],
- [],
- ),
- createStepAssertion('Configure MapBox SDK', true, null, 'ANDROID', 'Configure MapBox SDK'),
- createStepAssertion(
- 'Run Fastlane beta test',
- true,
- null,
- 'ANDROID',
- 'Run Fastlane beta test',
- [],
- [
- {key: 'S3_ACCESS_KEY', value: '***'},
- {key: 'S3_SECRET_ACCESS_KEY', value: '***'},
- {key: 'S3_BUCKET', value: 'ad-hoc-expensify-cash'},
- {key: 'S3_REGION', value: 'us-east-1'},
- {key: 'MYAPP_UPLOAD_STORE_PASSWORD', value: '***'},
- {key: 'MYAPP_UPLOAD_KEY_PASSWORD', value: '***'},
- ],
- ),
- createStepAssertion(
- 'Upload Artifact',
- true,
- null,
- 'ANDROID',
- 'Upload Artifact',
- [
- {key: 'name', value: 'android'},
- {key: 'path', value: './android_paths.json'},
- ],
- [],
- ),
- ] as const;
-
- steps.forEach((expectedStep, i) => {
- if (didExecute) {
- if (failsAt === -1 || i < failsAt) {
- // either whole job is successful, or steps up to this point are successful
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else if (i === failsAt) {
- // this is the failing step
- steps[i].status = 1;
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- // steps after failed one do not execute
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertIOSJobExecuted(workflowResult: Step[], ref = '', didExecute = true, failsAt = -1) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'IOS', 'Checkout', [{key: 'ref', value: ref}], []),
- createStepAssertion('Configure MapBox SDK', true, null, 'IOS', 'Configure MapBox SDK'),
- createStepAssertion('Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it', true, null, 'IOS', 'Creating .env.adhoc file based on staging', [], []),
- createStepAssertion('Setup Node', true, null, 'IOS', 'Setup Node', [], []),
- createStepAssertion('Setup XCode', true, null, 'IOS', 'Setup XCode', [], []),
- createStepAssertion(
- 'Setup Ruby',
- true,
- null,
- 'IOS',
- 'Setup Ruby',
- [
- {key: 'ruby-version', value: '2.7'},
- {key: 'bundler-cache', value: true},
- ],
- [],
- ),
- createStepAssertion('Cache Pod dependencies', true, null, 'IOS', 'Cache Pod dependencies', [
- {key: 'path', value: 'ios/Pods'},
- {key: 'key', value: 'Linux-pods-cache-'},
- ]),
- createStepAssertion('Compare Podfile.lock and Manifest.lock', true, null, 'IOS', 'Compare Podfile.lock and Manifest.lock'),
- createStepAssertion(
- 'Install cocoapods',
- true,
- null,
- 'IOS',
- 'Install cocoapods',
- [
- {key: 'timeout_minutes', value: '10'},
- {key: 'max_attempts', value: '5'},
- {key: 'command', value: 'cd ios && bundle exec pod install --verbose'},
- ],
- [],
- ),
- createStepAssertion('Decrypt AdHoc profile', true, null, 'IOS', 'Decrypt AdHoc profile', [], [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion(
- 'Decrypt AdHoc Notification Service profile',
- true,
- null,
- 'IOS',
- 'Decrypt AdHoc Notification Service profile',
- [],
- [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}],
- ),
- createStepAssertion('Decrypt certificate', true, null, 'IOS', 'Decrypt certificate', [], [{key: 'LARGE_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion(
- 'Configure AWS Credentials',
- true,
- null,
- 'IOS',
- 'Configure AWS Credentials',
- [
- {key: 'aws-access-key-id', value: '***'},
- {key: 'aws-secret-access-key', value: '***'},
- {key: 'aws-region', value: 'us-east-1'},
- ],
- [],
- ),
- createStepAssertion(
- 'Run Fastlane',
- true,
- null,
- 'IOS',
- 'Run Fastlane',
- [],
- [
- {key: 'S3_ACCESS_KEY', value: '***'},
- {key: 'S3_SECRET_ACCESS_KEY', value: '***'},
- {key: 'S3_BUCKET', value: 'ad-hoc-expensify-cash'},
- {key: 'S3_REGION', value: 'us-east-1'},
- ],
- ),
- createStepAssertion(
- 'Upload Artifact',
- true,
- null,
- 'IOS',
- 'Upload Artifact',
- [
- {key: 'name', value: 'ios'},
- {key: 'path', value: './ios_paths.json'},
- ],
- [],
- ),
- ] as const;
-
- steps.forEach((expectedStep, i) => {
- if (didExecute) {
- if (failsAt === -1 || i < failsAt) {
- // either whole job is successful, or steps up to this point are successful
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else if (i === failsAt) {
- // this is the failing step
- steps[i].status = 1;
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- // steps after failed one do not execute
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertDesktopJobExecuted(workflowResult: Step[], ref = '', didExecute = true, failsAt = -1) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'DESKTOP', 'Checkout', [{key: 'ref', value: ref}], []),
- createStepAssertion('Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it', true, null, 'DESKTOP', 'Creating .env.adhoc file based on staging', [], []),
- createStepAssertion('Setup Node', true, null, 'DESKTOP', 'Setup Node', [], []),
- createStepAssertion('Decrypt Developer ID Certificate', true, null, 'DESKTOP', 'Decrypt Developer ID Certificate', [], [{key: 'DEVELOPER_ID_SECRET_PASSPHRASE', value: '***'}]),
- createStepAssertion(
- 'Configure AWS Credentials',
- true,
- null,
- 'DESKTOP',
- 'Configure AWS Credentials',
- [
- {key: 'aws-access-key-id', value: '***'},
- {key: 'aws-secret-access-key', value: '***'},
- {key: 'aws-region', value: 'us-east-1'},
- ],
- [],
- ),
- createStepAssertion(
- 'Build desktop app for testing',
- true,
- null,
- 'DESKTOP',
- 'Build desktop app for testing',
- [],
- [
- {key: 'CSC_LINK', value: '***'},
- {key: 'CSC_KEY_PASSWORD', value: '***'},
- {key: 'APPLE_ID', value: '***'},
- {key: 'APPLE_APP_SPECIFIC_PASSWORD', value: '***'},
- {key: 'AWS_ACCESS_KEY_ID', value: '***'},
- {key: 'AWS_SECRET_ACCESS_KEY', value: '***'},
- ],
- ),
- ] as const;
-
- steps.forEach((expectedStep, i) => {
- if (didExecute) {
- if (failsAt === -1 || i < failsAt) {
- // either whole job is successful, or steps up to this point are successful
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else if (i === failsAt) {
- // this is the failing step
- steps[i].status = 1;
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- // steps after failed one do not execute
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertWebJobExecuted(workflowResult: Step[], ref = '', didExecute = true, failsAt = -1) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'WEB', 'Checkout', [{key: 'ref', value: ref}], []),
- createStepAssertion('Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it', true, null, 'WEB', 'Creating .env.adhoc file based on staging', [], []),
- createStepAssertion('Setup Node', true, null, 'WEB', 'Setup Node', [], []),
- createStepAssertion(
- 'Configure AWS Credentials',
- true,
- null,
- 'WEB',
- 'Configure AWS Credentials',
- [
- {key: 'aws-access-key-id', value: '***'},
- {key: 'aws-secret-access-key', value: '***'},
- {key: 'aws-region', value: 'us-east-1'},
- ],
- [],
- ),
- createStepAssertion('Build web for testing', true, null, 'WEB', 'Build web for testing', [], []),
- createStepAssertion('Build docs', true, null, 'WEB', 'Build docs', [], []),
- createStepAssertion('Deploy to S3 for internal testing', true, null, 'WEB', 'Deploy to S3 for internal testing', [], []),
- ] as const;
-
- steps.forEach((expectedStep, i) => {
- if (didExecute) {
- if (failsAt === -1 || i < failsAt) {
- // either whole job is successful, or steps up to this point are successful
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else if (i === failsAt) {
- // this is the failing step
- steps[i].status = 1;
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- // steps after failed one do not execute
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-function assertPostGithubCommentJobExecuted(
- workflowResult: Step[],
- ref = '',
- pullRequestNumber = '1234',
- didExecute = true,
- androidStatus = 'success',
- iOSStatus = 'success',
- desktopStatus = 'success',
- webStatus = 'success',
-) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'POSTGITHUBCOMMENT', 'Checkout', [{key: 'ref', value: ref}], []),
- createStepAssertion('Download Artifact', true, null, 'POSTGITHUBCOMMENT', 'Download Artifact', [], []),
- ];
-
- if (androidStatus === 'success') {
- steps.push(createStepAssertion('Read JSONs with android paths', true, null, 'POSTGITHUBCOMMENT', 'Read JSONs with android paths', [], []));
- }
- if (iOSStatus === 'success') {
- steps.push(createStepAssertion('Read JSONs with iOS paths', true, null, 'POSTGITHUBCOMMENT', 'Read JSONs with iOS paths', [], []));
- }
-
- steps.push(
- createStepAssertion(
- 'Publish links to apps for download',
- true,
- null,
- 'POSTGITHUBCOMMENT',
- 'Publish links to apps for download',
- [
- {key: 'PR_NUMBER', value: pullRequestNumber},
- {key: 'GITHUB_TOKEN', value: '***'},
- {key: 'ANDROID', value: androidStatus},
- {key: 'DESKTOP', value: desktopStatus},
- {key: 'IOS', value: iOSStatus},
- {key: 'WEB', value: webStatus},
- {key: 'ANDROID_LINK', value: androidStatus === 'success' ? 'http://dummy.android.link' : ''},
- {key: 'DESKTOP_LINK', value: `https://ad-hoc-expensify-cash.s3.amazonaws.com/desktop/${pullRequestNumber}/NewExpensify.dmg`},
- {key: 'IOS_LINK', value: iOSStatus === 'success' ? 'http://dummy.ios.link' : ''},
- {key: 'WEB_LINK', value: `https://${pullRequestNumber}.pr-testing.expensify.com`},
- ],
- [],
- ),
- );
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {
- assertValidateActorJobExecuted,
- assertGetBranchRefJobExecuted,
- assertAndroidJobExecuted,
- assertIOSJobExecuted,
- assertDesktopJobExecuted,
- assertWebJobExecuted,
- assertPostGithubCommentJobExecuted,
-};
diff --git a/workflow_tests/assertions/validateGithubActionsAssertions.ts b/workflow_tests/assertions/validateGithubActionsAssertions.ts
deleted file mode 100644
index 89eb444299ed..000000000000
--- a/workflow_tests/assertions/validateGithubActionsAssertions.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertVerifyJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'VERIFY', 'Checkout'),
- createStepAssertion('Setup Node', true, null, 'VERIFY', 'Setup Node', [], []),
- createStepAssertion('Verify Javascript Action Builds', true, null, 'VERIFY', 'Verify Javascript Action Builds', [], []),
- createStepAssertion('Validate actions and workflows', true, null, 'VERIFY', 'Validate actions and workflows', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertVerifyJobExecuted};
diff --git a/workflow_tests/assertions/verifyPodfileAssertions.ts b/workflow_tests/assertions/verifyPodfileAssertions.ts
deleted file mode 100644
index d837507ede1b..000000000000
--- a/workflow_tests/assertions/verifyPodfileAssertions.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertVerifyJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [
- createStepAssertion('Checkout', true, null, 'VERIFY', 'Checkout'),
- createStepAssertion('Setup Node', true, null, 'VERIFY', 'Setup Node', [], []),
- createStepAssertion('Verify podfile', true, null, 'VERIFY', 'Verify podfile', [], []),
- ] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-export default {assertVerifyJobExecuted};
diff --git a/workflow_tests/assertions/verifySignedCommitsAssertions.ts b/workflow_tests/assertions/verifySignedCommitsAssertions.ts
deleted file mode 100644
index 8aaabafa9d9d..000000000000
--- a/workflow_tests/assertions/verifySignedCommitsAssertions.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import type {Step} from '@kie/act-js';
-import {createStepAssertion} from '../utils/utils';
-
-function assertVerifySignedCommitsJobExecuted(workflowResult: Step[], didExecute = true) {
- const steps = [createStepAssertion('Verify signed commits', true, null, 'VERIFYSIGNEDCOMMITS', 'Verify signed commits', [{key: 'GITHUB_TOKEN', value: '***'}], [])] as const;
-
- steps.forEach((expectedStep) => {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- });
-}
-
-// eslint-disable-next-line import/prefer-default-export
-export default {assertVerifySignedCommitsJobExecuted};
diff --git a/workflow_tests/authorChecklist.test.ts b/workflow_tests/authorChecklist.test.ts
deleted file mode 100644
index a40b183f6d7a..000000000000
--- a/workflow_tests/authorChecklist.test.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/authorChecklistAssertions';
-import mocks from './mocks/authorChecklistMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'authorChecklist.yml'),
- dest: '.github/workflows/authorChecklist.yml',
- },
-];
-
-describe('test workflow authorChecklist', () => {
- const githubToken = 'dummy_github_token';
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testAuthorChecklistWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('pull request opened', () => {
- const event = 'pull_request_target';
- const eventOptions = {
- action: 'opened',
- };
- describe('actor is not OSBotify', () => {
- it('executes workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('authorChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result);
- });
- });
- describe('actor is OSBotify', () => {
- it('does not execute workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('authorChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result, false);
- });
- });
- });
- describe('pull request edited', () => {
- const event = 'pull_request_target';
- const eventOptions = {
- action: 'edited',
- };
- describe('actor is not OSBotify', () => {
- it('executes workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('authorChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result);
- });
- });
- describe('actor is OSBotify', () => {
- it('does not execute workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('authorChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result, false);
- });
- });
- });
- describe('pull request reopened', () => {
- const event = 'pull_request_target';
- const eventOptions = {
- action: 'reopened',
- };
- describe('actor is not OSBotify', () => {
- it('executes workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('authorChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result);
- });
- });
- describe('actor is OSBotify', () => {
- it('does not execute workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testAuthorChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'authorChecklist.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('authorChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result, false);
- });
- });
- });
-});
diff --git a/workflow_tests/cherryPick.test.ts b/workflow_tests/cherryPick.test.ts
deleted file mode 100644
index 964be3ec427d..000000000000
--- a/workflow_tests/cherryPick.test.ts
+++ /dev/null
@@ -1,396 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/cherryPickAssertions';
-import mocks from './mocks/cherryPickMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import type {MockJobs} from './utils/JobMocker';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'cherryPick.yml'),
- dest: '.github/workflows/cherryPick.yml',
- },
-];
-
-describe('test workflow cherryPick', () => {
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testCherryPickWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('manual workflow dispatch', () => {
- const event = 'workflow_dispatch';
- describe('actor is not deployer', () => {
- const actor = 'Dummy Author';
- it('workflow ends after validate job', async () => {
- const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- event,
- null,
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- null,
- {
- PULL_REQUEST_NUMBER: '1234',
- },
- );
- const testMockSteps: MockStep = {
- validateActor: mocks.CHERRYPICK__VALIDATEACTOR__FALSE__STEP_MOCKS,
- cherryPick: mocks.getCherryPickMockSteps(true, false),
- };
- const testMockJobs: MockJobs = {
- createNewVersion: {
- steps: mocks.CHERRYPICK__CREATENEWVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cherryPick', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertCherryPickJobExecuted(result, actor, '1234', false);
- });
- });
- describe('actor is OSBotify', () => {
- const actor = 'OSBotify';
- const mergeConflicts = false;
- const versionsMatch = true;
- it('behaviour is the same as with actor being the deployer', async () => {
- const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const testMockSteps: MockStep = {
- validateActor: mocks.CHERRYPICK__VALIDATEACTOR__FALSE__STEP_MOCKS,
- cherryPick: mocks.getCherryPickMockSteps(versionsMatch, mergeConflicts),
- };
- const testMockJobs: MockJobs = {
- createNewVersion: {
- steps: mocks.CHERRYPICK__CREATENEWVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- act = utils.setUpActParams(
- act,
- event,
- null,
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- null,
- {
- PULL_REQUEST_NUMBER: '1234',
- },
- );
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cherryPick', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertCherryPickJobExecuted(result, actor, '1234', true);
- });
- });
- describe('actor is a deployer', () => {
- const actor = 'Dummy Author';
- describe('no merge conflicts', () => {
- const mergeConflicts = false;
- describe('version match', () => {
- const versionsMatch = true;
- it('workflow executes, PR approved and merged automatically', async () => {
- const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const testMockSteps: MockStep = {
- validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS,
- };
- testMockSteps.cherryPick = mocks.getCherryPickMockSteps(versionsMatch, mergeConflicts);
- const testMockJobs: MockJobs = {
- createNewVersion: {
- steps: mocks.CHERRYPICK__CREATENEWVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- act = utils.setUpActParams(
- act,
- event,
- null,
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- null,
- {
- PULL_REQUEST_NUMBER: '1234',
- },
- );
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cherryPick', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertCherryPickJobExecuted(result, actor, '1234', true);
- });
- });
- describe('version does not match', () => {
- const versionsMatch = false;
- it('workflow executes, PR auto-assigned and commented, approved and merged automatically', async () => {
- const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const testMockSteps: MockStep = {
- validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS,
- };
- testMockSteps.cherryPick = mocks.getCherryPickMockSteps(versionsMatch, mergeConflicts);
- const testMockJobs: MockJobs = {
- createNewVersion: {
- steps: mocks.CHERRYPICK__CREATENEWVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- act = utils.setUpActParams(
- act,
- event,
- null,
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- null,
- {
- PULL_REQUEST_NUMBER: '1234',
- },
- );
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cherryPick', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertCherryPickJobExecuted(result, actor, '1234', true);
- });
- });
- });
- describe('merge conflicts', () => {
- const mergeConflicts = true;
- describe('version match', () => {
- const versionsMatch = true;
- it('workflow executes, PR auto-assigned and commented, not merged automatically', async () => {
- const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const testMockSteps: MockStep = {
- validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS,
- };
- testMockSteps.cherryPick = mocks.getCherryPickMockSteps(versionsMatch, mergeConflicts);
- const testMockJobs: MockJobs = {
- createNewVersion: {
- steps: mocks.CHERRYPICK__CREATENEWVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- act = utils.setUpActParams(
- act,
- event,
- null,
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- null,
- {
- PULL_REQUEST_NUMBER: '1234',
- },
- );
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cherryPick', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertCherryPickJobExecuted(result, actor, '1234', true, true);
- });
- });
- describe('version does not match', () => {
- const versionsMatch = false;
- it('workflow executes, PR auto-assigned and commented, not merged automatically', async () => {
- const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const testMockSteps: MockStep = {
- validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS,
- };
- testMockSteps.cherryPick = mocks.getCherryPickMockSteps(versionsMatch, mergeConflicts);
- const testMockJobs: MockJobs = {
- createNewVersion: {
- steps: mocks.CHERRYPICK__CREATENEWVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- act = utils.setUpActParams(
- act,
- event,
- null,
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- null,
- {
- PULL_REQUEST_NUMBER: '1234',
- },
- );
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cherryPick', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertCherryPickJobExecuted(result, actor, '1234', true, true);
- });
- });
- });
- });
- });
- describe('automatic trigger', () => {
- const event = 'pull_request';
- it('workflow does not execute', async () => {
- const repoPath = mockGithub.repo.getPath('testCherryPickWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cherryPick.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- event,
- null,
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- null,
- {
- PULL_REQUEST_NUMBER: '1234',
- },
- );
- const testMockSteps: MockStep = {
- validateActor: mocks.CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS,
- cherryPick: mocks.getCherryPickMockSteps(true, false),
- };
- const testMockJobs: MockJobs = {
- createNewVersion: {
- steps: mocks.CHERRYPICK__CREATENEWVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cherryPick.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('cherryPick', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertValidateActorJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertCherryPickJobExecuted(result, 'Dummy Author', '1234', false);
- });
- });
-});
diff --git a/workflow_tests/cla.test.ts b/workflow_tests/cla.test.ts
deleted file mode 100644
index 91691ec80587..000000000000
--- a/workflow_tests/cla.test.ts
+++ /dev/null
@@ -1,213 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {Step} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import {assertCLAJobExecuted} from './assertions/claAssertions';
-import {CLA__CLA__CHECK_MATCH__STEP_MOCKS, CLA__CLA__NO_MATCHES__STEP_MOCKS, CLA__CLA__RECHECK_MATCH__STEP_MOCKS} from './mocks/claMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'cla.yml'),
- dest: '.github/workflows/cla.yml',
- },
-];
-
-describe('test workflow cla', () => {
- const secrets: Record = {
- CLA_BOTIFY_TOKEN: 'dummy_cla_botify_token',
- };
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Author';
-
- // eslint-disable-next-line @typescript-eslint/require-await
- beforeAll(async () => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testClaWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub?.teardown();
- });
- describe('event is issue_comment', () => {
- const event = 'issue_comment';
- describe('no regex matches', () => {
- const commentBody = 'Comment body';
- const eventData = {
- action: 'created',
- issue: {
- pull_request: {
- number: 1234,
- },
- },
- comment: {
- body: commentBody,
- },
- };
- it('workflow executes, CLA assistant step not run', async () => {
- const repoPath = mockGithub?.repo.getPath('testClaWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventData, secrets, githubToken);
-
- const testMockSteps = {
- CLA: CLA__CLA__NO_MATCHES__STEP_MOCKS,
- };
-
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cla.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cla', expect.getState().currentTestName),
- });
-
- assertCLAJobExecuted(result, commentBody, `${repoPath}/remote/origin`, true, false);
- });
- });
- describe('check regex matches', () => {
- const commentBody = 'I have read the CLA Document and I hereby sign the CLA';
- const eventData = {
- action: 'created',
- issue: {
- pull_request: {
- number: 1234,
- },
- },
- comment: {
- body: commentBody,
- },
- };
- it('workflow executes, CLA assistant step run', async () => {
- const repoPath = mockGithub?.repo.getPath('testClaWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventData, secrets, githubToken);
-
- const testMockSteps = {
- CLA: CLA__CLA__CHECK_MATCH__STEP_MOCKS,
- };
-
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cla.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cla', expect.getState().currentTestName),
- });
-
- assertCLAJobExecuted(result, commentBody, `${repoPath}/remote/origin`, true, true);
- });
- });
- describe('re-check regex matches', () => {
- const commentBody = 'recheck';
- const eventData = {
- action: 'created',
- issue: {
- pull_request: {
- number: 1234,
- },
- },
- comment: {
- body: commentBody,
- },
- };
- it('workflow executes, CLA assistant step run', async () => {
- const repoPath = mockGithub?.repo.getPath('testClaWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventData, secrets, githubToken);
-
- const testMockSteps = {
- CLA: CLA__CLA__RECHECK_MATCH__STEP_MOCKS,
- };
-
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cla.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cla', expect.getState().currentTestName),
- });
-
- assertCLAJobExecuted(result, commentBody, `${repoPath}/remote/origin`, true, true);
- });
- });
- });
- describe('event is pull_request_target', () => {
- const event = 'pull_request_target';
- describe("no regex matches - there's no comment", () => {
- const eventData = {
- action: 'opened',
- issue: {
- pull_request: {
- number: 1234,
- },
- },
- };
- it('workflow executes, CLA assistant step still run', async () => {
- const repoPath = mockGithub?.repo.getPath('testClaWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventData, secrets, githubToken);
-
- const testMockSteps = {
- CLA: CLA__CLA__NO_MATCHES__STEP_MOCKS,
- };
-
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cla.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cla', expect.getState().currentTestName),
- });
-
- assertCLAJobExecuted(result, '', `${repoPath}/remote/origin`, true, true);
- });
- });
- });
- describe('different event', () => {
- const event = 'push';
- it('workflow does not execute', async () => {
- const eventData = {
- ref: 'main',
- };
-
- const repoPath = mockGithub?.repo.getPath('testClaWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'cla.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventData, secrets, githubToken);
-
- const testMockSteps = {
- CLA: CLA__CLA__NO_MATCHES__STEP_MOCKS,
- };
-
- const result: Step[] = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'cla.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('cla', expect.getState().currentTestName),
- });
-
- assertCLAJobExecuted(result, '', `${repoPath}/remote/origin`, false);
- });
- });
-});
diff --git a/workflow_tests/createNewVersion.test.ts b/workflow_tests/createNewVersion.test.ts
deleted file mode 100644
index 05dcc2b10073..000000000000
--- a/workflow_tests/createNewVersion.test.ts
+++ /dev/null
@@ -1,169 +0,0 @@
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/createNewVersionAssertions';
-import mocks from './mocks/createNewVersionMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000); // 90 sec
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'createNewVersion.yml'),
- dest: '.github/workflows/createNewVersion.yml',
- },
-];
-
-describe('test workflow createNewVersion', () => {
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testCreateNewVersionWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
-
- describe('event is workflow_call', () => {
- const event = 'workflow_call';
- const inputs = {
- SEMVER_LEVEL: 'BUILD',
- };
- const secrets = {
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- OS_BOTIFY_COMMIT_TOKEN: 'dummy_osbotify_commit_token',
- SLACK_WEBHOOK: 'dummy_webhook',
- OS_BOTIFY_APP_ID: 'os_botify_app_id',
- OS_BOTIFY_PRIVATE_KEY: 'os_botify_private_key',
- };
- const githubToken = 'dummy_github_token';
-
- describe('actor is admin', () => {
- const validateActorMockSteps = mocks.CREATENEWVERSION__VALIDATEACTOR__ADMIN__STEP_MOCKS;
- it('executes full workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: validateActorMockSteps,
- createNewVersion: mocks.CREATENEWVERSION__CREATENEWVERSION__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('createNewVersion', expect.getState().currentTestName),
- });
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result);
- });
- });
-
- describe('actor is writer', () => {
- const validateActorMockSteps = mocks.CREATENEWVERSION__VALIDATEACTOR__WRITER__STEP_MOCKS;
- it('executes full workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: validateActorMockSteps,
- createNewVersion: mocks.CREATENEWVERSION__CREATENEWVERSION__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('createNewVersion', expect.getState().currentTestName),
- });
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result);
- });
- });
-
- describe('actor is reader', () => {
- const validateActorMockSteps = mocks.CREATENEWVERSION__VALIDATEACTOR__NO_PERMISSION__STEP_MOCKS;
- it('stops after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: validateActorMockSteps,
- createNewVersion: mocks.CREATENEWVERSION__CREATENEWVERSION__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('createNewVersion', expect.getState().currentTestName),
- });
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result, 'BUILD', false);
- });
- });
-
- describe('one step fails', () => {
- it('announces failure on Slack', async () => {
- const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.CREATENEWVERSION__VALIDATEACTOR__ADMIN__STEP_MOCKS,
- createNewVersion: utils.deepCopy(mocks.CREATENEWVERSION__CREATENEWVERSION__STEP_MOCKS),
- };
- testMockSteps.createNewVersion[5] = utils.createMockStep('Commit new version', 'Commit new version', 'CREATENEWVERSION', [], [], {}, {}, false);
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('createNewVersion', expect.getState().currentTestName),
- });
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result, 'BUILD', true, false);
- });
- });
-
- it('chooses source branch depending on the SEMVER_LEVEL', async () => {
- const repoPath = mockGithub.repo.getPath('testCreateNewVersionWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, {SEMVER_LEVEL: 'MAJOR'});
- act = utils.setJobRunners(act, {createNewVersion: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.CREATENEWVERSION__VALIDATEACTOR__ADMIN__STEP_MOCKS,
- createNewVersion: mocks.CREATENEWVERSION__CREATENEWVERSION__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'createNewVersion.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('createNewVersion', expect.getState().currentTestName),
- });
- assertions.assertValidateActorJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result, 'MAJOR');
- });
- });
-});
diff --git a/workflow_tests/deploy.test.ts b/workflow_tests/deploy.test.ts
deleted file mode 100644
index 4edb3b252d38..000000000000
--- a/workflow_tests/deploy.test.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/deployAssertions';
-import mocks from './mocks/deployMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'deploy.yml'),
- dest: '.github/workflows/deploy.yml',
- },
-];
-
-describe('test workflow deploy', () => {
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testDeployWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- pushedBranches: ['staging', 'production'],
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
-
- const secrets = {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- OS_BOTIFY_APP_ID: 'os_botify_app_id',
- OS_BOTIFY_PRIVATE_KEY: 'os_botify_private_key',
- };
- describe('push', () => {
- it('to main - nothing triggered', async () => {
- const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {
- ref: 'refs/heads/main',
- },
- secrets,
- 'dummy_github_token',
- );
- const testMockSteps = {
- deployStaging: mocks.DEPLOY_STAGING_STEP_MOCKS,
- deployProduction: mocks.DEPLOY_PRODUCTION_STEP_MOCKS,
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deploy.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('deploy', expect.getState().currentTestName),
- });
- assertions.assertDeployStagingJobExecuted(result, false);
- assertions.assertDeployProductionJobExecuted(result, false);
- });
-
- it('to staging - deployStaging triggered', async () => {
- const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {
- ref: 'refs/heads/staging',
- },
- secrets,
- 'dummy_github_token',
- );
- const testMockSteps = {
- deployStaging: mocks.DEPLOY_STAGING_STEP_MOCKS,
- deployProduction: mocks.DEPLOY_PRODUCTION_STEP_MOCKS,
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deploy.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('deploy', expect.getState().currentTestName),
- });
- assertions.assertDeployStagingJobExecuted(result);
- assertions.assertDeployProductionJobExecuted(result, false);
- });
-
- it('to production - deployProduction triggered', async () => {
- const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {
- ref: 'refs/heads/production',
- },
- secrets,
- 'dummy_github_token',
- );
- const testMockSteps = {
- deployStaging: mocks.DEPLOY_STAGING_STEP_MOCKS,
- deployProduction: mocks.DEPLOY_PRODUCTION_STEP_MOCKS,
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deploy.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('deploy', expect.getState().currentTestName),
- });
- assertions.assertDeployStagingJobExecuted(result, false);
- assertions.assertDeployProductionJobExecuted(result);
- });
- });
-
- it('different event than push - workflow does not execute', async () => {
- const repoPath = mockGithub.repo.getPath('testDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'deploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const testMockSteps = {
- deployStaging: mocks.DEPLOY_STAGING_STEP_MOCKS,
- deployProduction: mocks.DEPLOY_PRODUCTION_STEP_MOCKS,
- };
-
- // pull_request
- act = utils.setUpActParams(act, 'pull_request', {head: {ref: 'main'}}, secrets, 'dummy_github_token');
- let result = await act.runEvent('pull_request', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('deploy', expect.getState().currentTestName),
- });
- assertions.assertDeployStagingJobExecuted(result, false);
- assertions.assertDeployProductionJobExecuted(result, false);
-
- // workflow_dispatch
- act = utils.setUpActParams(act, 'workflow_dispatch', {}, secrets, 'dummy_github_token');
- result = await act.runEvent('workflow_dispatch', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('deploy', expect.getState().currentTestName),
- });
- assertions.assertDeployStagingJobExecuted(result, false);
- assertions.assertDeployProductionJobExecuted(result, false);
- });
-});
diff --git a/workflow_tests/deployBlocker.test.ts b/workflow_tests/deployBlocker.test.ts
deleted file mode 100644
index eb4cdc2c9497..000000000000
--- a/workflow_tests/deployBlocker.test.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/deployBlockerAssertions';
-import mocks from './mocks/deployBlockerMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'deployBlocker.yml'),
- dest: '.github/workflows/deployBlocker.yml',
- },
-];
-
-describe('test workflow deployBlocker', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Author';
- const secrets = {
- OS_BOTIFY_TOKEN: 'dummy_osbotify_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- };
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testDeployBlockerWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
-
- // if any branches besides main are need add: pushedBranches: ['staging', 'production'],
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('issue labeled', () => {
- const event = 'issues';
- const eventOptions = {
- action: 'labeled',
- label: {
- name: 'DeployBlockerCash',
- },
- issue: {
- title: 'Labeled issue title',
- number: '1234',
- html_url: 'http://issue.html.url',
- },
- };
- describe('label is DeployBlockerCash', () => {
- const testEventOptions = utils.deepCopy(eventOptions);
- testEventOptions.label = {name: 'DeployBlockerCash'};
- it('runs the workflow and announces success on Slack', async () => {
- const repoPath = mockGithub.repo.getPath('testDeployBlockerWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, testEventOptions, secrets, githubToken, {}, {});
- const testMockSteps = {
- deployBlocker: mocks.DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS,
- };
- const testMockJobs = {
- updateChecklist: {
- steps: mocks.DEPLOYBLOCKER__UPDATECHECKLIST__STEP_MOCKS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('deployBlocker', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertUpdateChecklistJobExecuted(result);
- assertions.assertDeployBlockerJobExecuted(result);
- });
- describe('one step fails', () => {
- it('announces failure on Slack', async () => {
- const repoPath = mockGithub.repo.getPath('testDeployBlockerWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, testEventOptions, secrets, githubToken, {}, {});
- const testMockSteps = {
- deployBlocker: utils.deepCopy(mocks.DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS),
- };
- testMockSteps.deployBlocker[1] = utils.createMockStep(
- 'Give the issue/PR the Hourly, Engineering labels',
- 'Give the issue/PR the Hourly, Engineering labels',
- 'DEPLOYBLOCKER',
- [],
- ['GITHUB_TOKEN'],
- null,
- null,
- false,
- );
- const testMockJobs = {
- updateChecklist: {
- steps: mocks.DEPLOYBLOCKER__UPDATECHECKLIST__STEP_MOCKS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('deployBlocker', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertUpdateChecklistJobExecuted(result);
- assertions.assertDeployBlockerJobExecuted(result, true, false, 1);
- });
- });
- });
- describe('label is different', () => {
- const testEventOptions = utils.deepCopy(eventOptions);
- testEventOptions.label = {name: 'Different Label'};
- it('does not run workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testDeployBlockerWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, testEventOptions, secrets, githubToken, {}, {});
- const testMockSteps = {
- deployBlocker: mocks.DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS,
- };
- const testMockJobs = {
- updateChecklist: {
- steps: mocks.DEPLOYBLOCKER__UPDATECHECKLIST__STEP_MOCKS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'deployBlocker.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('deployBlocker', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertUpdateChecklistJobExecuted(result, false);
- assertions.assertDeployBlockerJobExecuted(result, false);
- });
- });
- });
-});
diff --git a/workflow_tests/failureNotifier.test.ts b/workflow_tests/failureNotifier.test.ts
deleted file mode 100644
index 772cd5d28050..000000000000
--- a/workflow_tests/failureNotifier.test.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/failureNotifierAssertions';
-import mocks from './mocks/failureNotifierMocks';
-import ExtendedAct from './utils/ExtendedAct';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'failureNotifier.yml'),
- dest: '.github/workflows/failureNotifier.yml',
- },
-] as const satisfies CreateRepositoryFile[];
-
-describe('test workflow failureNotifier', () => {
- const actor = 'Dummy Actor';
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testFailureNotifierWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
-
- // if any branches besides main are needed add: pushedBranches: ['staging', 'production'],
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- it('runs the notify failure when main fails', async () => {
- const repoPath = mockGithub.repo.getPath('testFailureNotifierWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'failureNotifier.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const event = 'workflow_run';
- act = act.setEvent({
- // eslint-disable-next-line @typescript-eslint/naming-convention
- workflow_run: {
- name: 'Process new code merged to main',
- conclusion: 'failure',
- },
- });
- const testMockSteps = {
- notifyFailure: mocks.FAILURENOTIFIER__NOTIFYFAILURE__STEP_MOCKS,
- } as const satisfies MockStep;
-
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'failureNotifier.yml'),
- mockSteps: testMockSteps,
- actor,
- });
-
- // assert execution with imported assertions
- assertions.assertNotifyFailureJobExecuted(result);
- });
-});
diff --git a/workflow_tests/finishReleaseCycle.test.ts b/workflow_tests/finishReleaseCycle.test.ts
deleted file mode 100644
index 7f81137807f4..000000000000
--- a/workflow_tests/finishReleaseCycle.test.ts
+++ /dev/null
@@ -1,240 +0,0 @@
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/finishReleaseCycleAssertions';
-import mocks from './mocks/finishReleaseCycleMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import type {MockJobs} from './utils/JobMocker';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'finishReleaseCycle.yml'),
- dest: '.github/workflows/finishReleaseCycle.yml',
- },
-];
-
-describe('test workflow finishReleaseCycle', () => {
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testFinishReleaseCycleWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- const secrets = {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- OS_BOTIFY_APP_ID: 'os_botify_app_id',
- OS_BOTIFY_PRIVATE_KEY: 'os_botify_private_key',
- };
- describe('issue closed', () => {
- describe('issue has StagingDeployCash', () => {
- describe('actor is a team member', () => {
- describe('no deploy blockers', () => {
- it('production updated, new version created', async () => {
- const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'closed',
- type: 'closed',
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- number: '1234',
- },
- },
- secrets,
- );
- const testMockSteps = {
- validate: mocks.FINISHRELEASECYCLE__VALIDATE__TEAM_MEMBER_NO_BLOCKERS__STEP_MOCKS,
- updateProduction: mocks.FINISHRELEASECYCLE__UPDATEPRODUCTION__STEP_MOCKS,
- updateStaging: mocks.FINISHRELEASECYCLE__UPDATESTAGING__STEP_MOCKS,
- };
- const testMockJobs: MockJobs = {
- createNewPatchVersion: {
- steps: mocks.FINISHRELEASECYCLE__CREATENEWPATCHVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('finishReleaseCycle', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertValidateJobExecuted(result, '1234');
- assertions.assertUpdateProductionJobExecuted(result);
- assertions.assertCreateNewPatchVersionJobExecuted(result);
- assertions.assertUpdateStagingJobExecuted(result);
- });
- });
- describe('deploy blockers', () => {
- it('production not updated, new version not created, issue reopened', async () => {
- const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'closed',
- type: 'closed',
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- number: '1234',
- },
- },
- secrets,
- );
- const testMockSteps = {
- validate: mocks.FINISHRELEASECYCLE__VALIDATE__TEAM_MEMBER_BLOCKERS__STEP_MOCKS,
- updateProduction: mocks.FINISHRELEASECYCLE__UPDATEPRODUCTION__STEP_MOCKS,
- updateStaging: mocks.FINISHRELEASECYCLE__UPDATESTAGING__STEP_MOCKS,
- };
- const testMockJobs = {
- createNewPatchVersion: {
- steps: mocks.FINISHRELEASECYCLE__CREATENEWPATCHVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('finishReleaseCycle', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertValidateJobExecuted(result, '1234', true, true, true);
- assertions.assertUpdateProductionJobExecuted(result, false);
- assertions.assertCreateNewPatchVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- });
- });
- });
- describe('actor is not a team member', () => {
- it('production not updated, new version not created, issue reopened', async () => {
- const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'closed',
- type: 'closed',
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- number: '1234',
- },
- },
- secrets,
- );
- const testMockSteps = {
- validate: mocks.FINISHRELEASECYCLE__VALIDATE__NOT_TEAM_MEMBER_NO_BLOCKERS__STEP_MOCKS,
- updateProduction: mocks.FINISHRELEASECYCLE__UPDATEPRODUCTION__STEP_MOCKS,
- updateStaging: mocks.FINISHRELEASECYCLE__UPDATESTAGING__STEP_MOCKS,
- };
- const testMockJobs = {
- createNewPatchVersion: {
- steps: mocks.FINISHRELEASECYCLE__CREATENEWPATCHVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('finishReleaseCycle', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertValidateJobExecuted(result, '1234', true, false, false);
- assertions.assertUpdateProductionJobExecuted(result, false);
- assertions.assertCreateNewPatchVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- });
- });
- });
- describe('issue does not have StagingDeployCash', () => {
- it('validate job not run', async () => {
- const repoPath = mockGithub.repo.getPath('testFinishReleaseCycleWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'closed',
- type: 'closed',
- issue: {
- labels: [{name: 'Some'}, {name: 'Other'}, {name: 'Labels'}],
- number: '1234',
- },
- },
- secrets,
- );
- const testMockSteps = {
- validate: mocks.FINISHRELEASECYCLE__VALIDATE__TEAM_MEMBER_NO_BLOCKERS__STEP_MOCKS,
- updateProduction: mocks.FINISHRELEASECYCLE__UPDATEPRODUCTION__STEP_MOCKS,
- updateStaging: mocks.FINISHRELEASECYCLE__UPDATESTAGING__STEP_MOCKS,
- };
- const testMockJobs = {
- createNewPatchVersion: {
- steps: mocks.FINISHRELEASECYCLE__CREATENEWPATCHVERSION__STEP_MOCKS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'finishReleaseCycle.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('finishReleaseCycle', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertValidateJobExecuted(result, '1234', false);
- assertions.assertUpdateProductionJobExecuted(result, false);
- assertions.assertCreateNewPatchVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- });
- });
- });
-});
diff --git a/workflow_tests/jest.config.ts b/workflow_tests/jest.config.ts
deleted file mode 100644
index 8156e449039f..000000000000
--- a/workflow_tests/jest.config.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {Config} from 'jest';
-
-const config: Config = {
- verbose: true,
- transform: {
- '^.+\\.(js|jsx|ts|tsx)$': 'ts-jest',
- },
- clearMocks: true,
- resetMocks: true,
-};
-
-export default config;
diff --git a/workflow_tests/lint.test.ts b/workflow_tests/lint.test.ts
deleted file mode 100644
index e0b0fb13859d..000000000000
--- a/workflow_tests/lint.test.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/lintAssertions';
-import mocks from './mocks/lintMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'lint.yml'),
- dest: '.github/workflows/lint.yml',
- },
-];
-
-describe('test workflow lint', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testLintWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
-
- // if any branches besides main are need add: pushedBranches: ['staging', 'production'],
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('event is workflow_call', () => {
- const event = 'workflow_call';
- const eventOptions = {};
- it('runs the lint', async () => {
- const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- lint: mocks.LINT__LINT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lint.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('lint', expect.getState().currentTestName),
- });
-
- assertions.assertLintJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- const testActor = 'OSBotify';
- it('runs the lint', async () => {
- const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- lint: mocks.LINT__LINT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lint.yml'),
- mockSteps: testMockSteps,
- actor: testActor,
- logFile: utils.getLogFilePath('lint', expect.getState().currentTestName),
- });
-
- assertions.assertLintJobExecuted(result);
- });
- });
- });
- describe('event is pull_request', () => {
- const event = 'pull_request';
- describe('pull_request is opened', () => {
- const eventOptions = {
- action: 'opened',
- };
- it('runs the lint', async () => {
- const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- lint: mocks.LINT__LINT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lint.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('lint', expect.getState().currentTestName),
- });
-
- assertions.assertLintJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- const testActor = 'OSBotify';
- it('does not run the lint', async () => {
- const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- lint: mocks.LINT__LINT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lint.yml'),
- mockSteps: testMockSteps,
- actor: testActor,
- logFile: utils.getLogFilePath('lint', expect.getState().currentTestName),
- });
-
- assertions.assertLintJobExecuted(result, false);
- });
- });
- });
- describe('pull_request is synchronized', () => {
- const eventOptions = {
- action: 'synchronize',
- };
- it('runs the lint', async () => {
- const repoPath = mockGithub.repo.getPath('testLintWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lint.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- lint: mocks.LINT__LINT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lint.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('lint', expect.getState().currentTestName),
- });
-
- assertions.assertLintJobExecuted(result);
- });
- });
- });
-});
diff --git a/workflow_tests/lockDeploys.test.ts b/workflow_tests/lockDeploys.test.ts
deleted file mode 100644
index 7ffb4ed87b7a..000000000000
--- a/workflow_tests/lockDeploys.test.ts
+++ /dev/null
@@ -1,462 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/lockDeploysAssertions';
-import mocks from './mocks/lockDeploysMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'lockDeploys.yml'),
- dest: '.github/workflows/lockDeploys.yml',
- },
-];
-
-describe('test workflow lockDeploys', () => {
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testLockDeploysWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('issue labeled', () => {
- describe('label is LockCashDeploys', () => {
- describe('issue has StagingDeployCash', () => {
- describe('actor is not OSBotify', () => {
- it('job triggered, comment left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: '🔐 LockCashDeploys 🔐',
- },
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result);
- });
-
- it('one step fails, comment not left in StagingDeployCash, announced failure in Slack', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: '🔐 LockCashDeploys 🔐',
- },
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- testMockSteps.lockStagingDeploys[1] = utils.createMockStep(
- 'Wait for staging deploys to finish',
- 'Waiting for staging deploys to finish',
- 'LOCKSTAGINGDEPLOYS',
- ['GITHUB_TOKEN'],
- [],
- null,
- null,
- false,
- );
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobFailedAfterFirstStep(result);
- });
- });
-
- describe('actor is OSBotify', () => {
- it('job not triggered, comment not left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: '🔐 LockCashDeploys 🔐',
- },
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result, false);
- });
- });
- });
-
- describe('issue does not have StagingDeployCash', () => {
- describe('actor is not OSBotify', () => {
- it('job not triggered, comment not left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: '🔐 LockCashDeploys 🔐',
- },
- issue: {
- labels: [{name: 'Some'}, {name: 'Other'}, {name: 'Labels'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result, false);
- });
- });
-
- describe('actor is OSBotify', () => {
- it('job not triggered, comment not left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: '🔐 LockCashDeploys 🔐',
- },
- issue: {
- labels: [{name: 'Some'}, {name: 'Other'}, {name: 'Labels'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result, false);
- });
- });
- });
- });
-
- describe('label is not LockCashDeploys', () => {
- describe('issue has StagingDeployCash', () => {
- describe('actor is not OSBotify', () => {
- it('job not triggered, comment not left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: 'Some different label',
- },
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result, false);
- });
- });
-
- describe('actor is OSBotify', () => {
- it('job not triggered, comment not left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: 'Some different label',
- },
- issue: {
- labels: [{name: 'StagingDeployCash'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result, false);
- });
- });
- });
-
- describe('issue does not have StagingDeployCash', () => {
- describe('actor is not OSBotify', () => {
- it('job not triggered, comment not left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: 'Some other label',
- },
- issue: {
- labels: [{name: 'Some'}, {name: 'Other'}, {name: 'Labels'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result, false);
- });
- });
-
- describe('actor is OSBotify', () => {
- it('job not triggered, comment not left in StagingDeployCash', async () => {
- const repoPath = mockGithub.repo.getPath('testLockDeploysWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'issues',
- {
- action: 'labeled',
- type: 'labeled',
- label: {
- name: 'Some other label',
- },
- issue: {
- labels: [{name: 'Some'}, {name: 'Other'}, {name: 'Labels'}],
- },
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- lockStagingDeploys: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- lockStagingDeploys: mocks.LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
- };
- const result = await act.runEvent('issues', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'lockDeploys.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('lockDeploys', expect.getState().currentTestName),
- });
-
- assertions.assertlockStagingDeploysJobExecuted(result, false);
- });
- });
- });
- });
- });
-});
diff --git a/workflow_tests/mocks/authorChecklistMocks.ts b/workflow_tests/mocks/authorChecklistMocks.ts
deleted file mode 100644
index 34e6b0984e83..000000000000
--- a/workflow_tests/mocks/authorChecklistMocks.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {StepIdentifier} from '@kie/act-js';
-import {createMockStep} from '../utils/utils';
-
-// checklist
-const AUTHORCHECKLIST__CHECKLIST__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'CHECKLIST');
-const AUTHORCHECKLIST__CHECKLIST__AUTHORCHECKLIST_JS__STEP_MOCK = createMockStep('authorChecklist.ts', 'Running authorChecklist.ts', 'CHECKLIST', ['GITHUB_TOKEN'], []);
-const AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS = [
- AUTHORCHECKLIST__CHECKLIST__CHECKOUT__STEP_MOCK,
- AUTHORCHECKLIST__CHECKLIST__AUTHORCHECKLIST_JS__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-export default {
- AUTHORCHECKLIST__CHECKLIST__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/cherryPickMocks.ts b/workflow_tests/mocks/cherryPickMocks.ts
deleted file mode 100644
index 13d7ebf95bfd..000000000000
--- a/workflow_tests/mocks/cherryPickMocks.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {StepIdentifier} from '@kie/act-js';
-import {createMockStep} from '../utils/utils';
-
-// validateactor
-const CHERRYPICK__VALIDATEACTOR__CHECK_IF_USER_IS_DEPLOYER_TRUE__STEP_MOCK = createMockStep(
- 'Check if user is deployer',
- 'Checking if user is a deployer',
- 'VALIDATEACTOR',
- [],
- ['GITHUB_TOKEN'],
- {IS_DEPLOYER: true},
-);
-const CHERRYPICK__VALIDATEACTOR__CHECK_IF_USER_IS_DEPLOYER_FALSE__STEP_MOCK = createMockStep(
- 'Check if user is deployer',
- 'Checking if user is a deployer',
- 'VALIDATEACTOR',
- [],
- ['GITHUB_TOKEN'],
- {IS_DEPLOYER: false},
-);
-const CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS = [CHERRYPICK__VALIDATEACTOR__CHECK_IF_USER_IS_DEPLOYER_TRUE__STEP_MOCK];
-const CHERRYPICK__VALIDATEACTOR__FALSE__STEP_MOCKS = [CHERRYPICK__VALIDATEACTOR__CHECK_IF_USER_IS_DEPLOYER_FALSE__STEP_MOCK];
-
-// createnewversion
-const CHERRYPICK__CREATENEWVERSION__CREATE_NEW_VERSION__STEP_MOCK = createMockStep(
- 'Create new version',
- 'Creating new version',
- 'CREATENEWVERSION',
- [],
- [],
- {NEW_VERSION: '1.2.3'},
- null,
- true,
- 'createNewVersion',
-);
-const CHERRYPICK__CREATENEWVERSION__STEP_MOCKS = [CHERRYPICK__CREATENEWVERSION__CREATE_NEW_VERSION__STEP_MOCK];
-
-// cherrypick
-const CHERRYPICK__CHERRYPICK__CHECKOUT_STAGING_BRANCH__STEP_MOCK = createMockStep('Checkout staging branch', 'Checking out staging branch', 'CHERRYPICK', ['ref', 'token'], []);
-const CHERRYPICK__CHERRYPICK__SET_UP_GIT_FOR_OSBOTIFY__STEP_MOCK = createMockStep('Set up git for OSBotify', 'Setting up git for OSBotify', 'CHERRYPICK', ['GPG_PASSPHRASE'], [], {
- OS_BOTIFY_API_TOKEN: 'os_botify_api_token',
-});
-const CHERRYPICK__CHERRYPICK__GET_PREVIOUS_APP_VERSION__STEP_MOCK = createMockStep('Get previous app version', 'Get previous app version', 'CHERRYPICK', ['SEMVER_LEVEL']);
-const CHERRYPICK__CHERRYPICK__FETCH_HISTORY_OF_RELEVANT_REFS__STEP_MOCK = createMockStep('Fetch history of relevant refs', 'Fetch history of relevant refs', 'CHERRYPICK');
-const CHERRYPICK__CHERRYPICK__GET_VERSION_BUMP_COMMIT__STEP_MOCK = createMockStep('Get version bump commit', 'Get version bump commit', 'CHERRYPICK', [], [], {
- VERSION_BUMP_SHA: 'version_bump_sha',
-});
-const CHERRYPICK__CHERRYPICK__GET_MERGE_COMMIT_FOR_PULL_REQUEST_TO_CP__STEP_MOCK = createMockStep(
- 'Get merge commit for pull request to CP',
- 'Get merge commit for pull request to CP',
- 'CHERRYPICK',
- ['GITHUB_TOKEN', 'USER', 'PULL_REQUEST_NUMBER'],
- [],
- {MERGE_ACTOR: '@dummyauthor'},
-);
-const CHERRYPICK__CHERRYPICK__CHERRY_PICK_THE_VERSION_BUMP_TO_STAGING__STEP_MOCK = createMockStep(
- 'Cherry-pick the version-bump to staging',
- 'Cherry-picking the version-bump to staging',
- 'CHERRYPICK',
- [],
- [],
-);
-const CHERRYPICK__CHERRYPICK__CHERRY_PICK_THE_MERGE_COMMIT_OF_TARGET_PR_TO_NEW_BRANCH__HAS_NO_CONFLICTS__STEP_MOCK = createMockStep(
- 'Cherry-pick the merge commit of target PR',
- 'Cherry-picking the merge commit of target PR',
- 'CHERRYPICK',
- [],
- [],
- {HAS_CONFLICTS: false},
-);
-// eslint-disable-next-line rulesdir/no-negated-variables
-const CHERRYPICK__CHERRYPICK__CHERRY_PICK_THE_MERGE_COMMIT_OF_TARGET_PR_TO_NEW_BRANCH__HAS_CONFLICTS__STEP_MOCK = createMockStep(
- 'Cherry-pick the merge commit of target PR',
- 'Cherry-picking the merge commit of target PR',
- 'CHERRYPICK',
- [],
- [],
- {HAS_CONFLICTS: true},
-);
-const CHERRYPICK__CHERRYPICK__PUSH_CHANGES__STEP_MOCK = createMockStep('Push changes', 'Pushing changes', 'CHERRYPICK', [], []);
-const CHERRYPICK__CHERRYPICK__CREATE_PULL_REQUEST_TO_MANUALLY_FINISH_CP__STEP_MOCK = createMockStep(
- 'Create Pull Request to manually finish CP',
- 'Creating Pull Request to manually finish CP',
- 'CHERRYPICK',
- [],
- ['GITHUB_TOKEN'],
-);
-const CHERRYPICK__CHERRYPICK__ANNOUNCES_A_CP_FAILURE_IN_THE_ANNOUNCE_SLACK_ROOM__STEP_MOCK = createMockStep(
- 'Announces a CP failure in the #announce Slack room',
- 'Announcing a CP failure',
- 'CHERRYPICK',
- ['status'],
- ['GITHUB_TOKEN', 'SLACK_WEBHOOK_URL'],
-);
-
-const getCherryPickMockSteps = (upToDate: boolean, hasConflicts: boolean): StepIdentifier[] => [
- CHERRYPICK__CHERRYPICK__CHECKOUT_STAGING_BRANCH__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__SET_UP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__GET_PREVIOUS_APP_VERSION__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__FETCH_HISTORY_OF_RELEVANT_REFS__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__GET_VERSION_BUMP_COMMIT__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__GET_MERGE_COMMIT_FOR_PULL_REQUEST_TO_CP__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__CHERRY_PICK_THE_VERSION_BUMP_TO_STAGING__STEP_MOCK,
- hasConflicts
- ? CHERRYPICK__CHERRYPICK__CHERRY_PICK_THE_MERGE_COMMIT_OF_TARGET_PR_TO_NEW_BRANCH__HAS_CONFLICTS__STEP_MOCK
- : CHERRYPICK__CHERRYPICK__CHERRY_PICK_THE_MERGE_COMMIT_OF_TARGET_PR_TO_NEW_BRANCH__HAS_NO_CONFLICTS__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__PUSH_CHANGES__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__CREATE_PULL_REQUEST_TO_MANUALLY_FINISH_CP__STEP_MOCK,
- CHERRYPICK__CHERRYPICK__ANNOUNCES_A_CP_FAILURE_IN_THE_ANNOUNCE_SLACK_ROOM__STEP_MOCK,
-];
-
-export default {CHERRYPICK__CREATENEWVERSION__STEP_MOCKS, CHERRYPICK__VALIDATEACTOR__FALSE__STEP_MOCKS, CHERRYPICK__VALIDATEACTOR__TRUE__STEP_MOCKS, getCherryPickMockSteps};
diff --git a/workflow_tests/mocks/claMocks.ts b/workflow_tests/mocks/claMocks.ts
deleted file mode 100644
index ca065510cd4a..000000000000
--- a/workflow_tests/mocks/claMocks.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// cla
-const CLA__CLA__CLA_COMMENT_CHECK__NO_MATCH__STEP_MOCK = createMockStep('CLA comment check', 'CLA comment check', 'CLA', ['text', 'regex'], [], {match: ''});
-const CLA__CLA__CLA_COMMENT_CHECK__MATCH__STEP_MOCK = createMockStep('CLA comment check', 'CLA comment check', 'CLA', ['text', 'regex'], [], {
- match: 'I have read the CLA Document and I hereby sign the CLA',
-});
-const CLA__CLA__CLA_COMMENT_RE_CHECK__NO_MATCH__STEP_MOCK = createMockStep('CLA comment re-check', 'CLA comment re-check', 'CLA', ['text', 'regex'], [], {match: ''});
-const CLA__CLA__CLA_COMMENT_RE_CHECK__MATCH__STEP_MOCK = createMockStep('CLA comment re-check', 'CLA comment re-check', 'CLA', ['text', 'regex'], [], {match: 'recheck'});
-const CLA__CLA__CLA_ASSISTANT__STEP_MOCK = createMockStep(
- 'CLA Assistant',
- 'CLA Assistant',
- 'CLA',
- ['path-to-signatures', 'path-to-document', 'branch', 'remote-organization-name', 'remote-repository-name', 'lock-pullrequest-aftermerge', 'allowlist'],
- ['GITHUB_TOKEN', 'PERSONAL_ACCESS_TOKEN'],
-);
-const CLA__CLA__NO_MATCHES__STEP_MOCKS = [CLA__CLA__CLA_COMMENT_CHECK__NO_MATCH__STEP_MOCK, CLA__CLA__CLA_COMMENT_RE_CHECK__NO_MATCH__STEP_MOCK, CLA__CLA__CLA_ASSISTANT__STEP_MOCK];
-const CLA__CLA__CHECK_MATCH__STEP_MOCKS = [CLA__CLA__CLA_COMMENT_CHECK__MATCH__STEP_MOCK, CLA__CLA__CLA_COMMENT_RE_CHECK__NO_MATCH__STEP_MOCK, CLA__CLA__CLA_ASSISTANT__STEP_MOCK];
-const CLA__CLA__RECHECK_MATCH__STEP_MOCKS = [CLA__CLA__CLA_COMMENT_CHECK__NO_MATCH__STEP_MOCK, CLA__CLA__CLA_COMMENT_RE_CHECK__MATCH__STEP_MOCK, CLA__CLA__CLA_ASSISTANT__STEP_MOCK];
-
-export {CLA__CLA__NO_MATCHES__STEP_MOCKS, CLA__CLA__CHECK_MATCH__STEP_MOCKS, CLA__CLA__RECHECK_MATCH__STEP_MOCKS};
diff --git a/workflow_tests/mocks/createNewVersionMocks.ts b/workflow_tests/mocks/createNewVersionMocks.ts
deleted file mode 100644
index dd094e6459e8..000000000000
--- a/workflow_tests/mocks/createNewVersionMocks.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {StepIdentifier} from '@kie/act-js';
-import {createMockStep} from '../utils/utils';
-
-// validateactor
-const CREATENEWVERSION__VALIDATEACTOR__GET_USER_PERMISSIONS__ADMIN__STEP_MOCK = createMockStep('Get user permissions', 'Get user permissions', 'VALIDATEACTOR', [], ['GITHUB_TOKEN'], {
- PERMISSION: 'admin',
-});
-const CREATENEWVERSION__VALIDATEACTOR__GET_USER_PERMISSIONS__WRITE__STEP_MOCK = createMockStep('Get user permissions', 'Get user permissions', 'VALIDATEACTOR', [], ['GITHUB_TOKEN'], {
- PERMISSION: 'write',
-});
-const CREATENEWVERSION__VALIDATEACTOR__GET_USER_PERMISSIONS__NONE__STEP_MOCK = createMockStep('Get user permissions', 'Get user permissions', 'VALIDATEACTOR', [], ['GITHUB_TOKEN'], {
- PERMISSION: 'read',
-});
-const CREATENEWVERSION__VALIDATEACTOR__ADMIN__STEP_MOCKS = [CREATENEWVERSION__VALIDATEACTOR__GET_USER_PERMISSIONS__ADMIN__STEP_MOCK] as const satisfies StepIdentifier[];
-const CREATENEWVERSION__VALIDATEACTOR__WRITER__STEP_MOCKS = [CREATENEWVERSION__VALIDATEACTOR__GET_USER_PERMISSIONS__WRITE__STEP_MOCK] as const satisfies StepIdentifier[];
-const CREATENEWVERSION__VALIDATEACTOR__NO_PERMISSION__STEP_MOCKS = [CREATENEWVERSION__VALIDATEACTOR__GET_USER_PERMISSIONS__NONE__STEP_MOCK] as const satisfies StepIdentifier[];
-
-// createnewversion
-const CREATENEWVERSION__CREATENEWVERSION__RUN_TURNSTYLE__STEP_MOCK = createMockStep('Run turnstyle', 'Run turnstyle', 'CREATENEWVERSION', ['poll-interval-seconds'], ['GITHUB_TOKEN']);
-const CREATENEWVERSION__CREATENEWVERSION__CHECK_OUT__STEP_MOCK = createMockStep('Check out', 'Check out', 'CREATENEWVERSION', ['ref', 'token'], []);
-const CREATENEWVERSION__CREATENEWVERSION__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK = createMockStep('Setup git for OSBotify', 'Setup git for OSBotify', 'CREATENEWVERSION', ['GPG_PASSPHRASE'], []);
-const CREATENEWVERSION__CREATENEWVERSION__GENERATE_VERSION__STEP_MOCK = createMockStep('Generate version', 'Generate version', 'CREATENEWVERSION', ['GITHUB_TOKEN', 'SEMVER_LEVEL'], []);
-const CREATENEWVERSION__CREATENEWVERSION__COMMIT_NEW_VERSION__STEP_MOCK = createMockStep('Commit new version', 'Commit new version', 'CREATENEWVERSION', [], []);
-const CREATENEWVERSION__CREATENEWVERSION__UPDATE_MAIN_BRANCH__STEP_MOCK = createMockStep('Update main branch', 'Update main branch', 'CREATENEWVERSION', [], []);
-const CREATENEWVERSION__CREATENEWVERSION__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK = createMockStep(
- 'Announce failed workflow in Slack',
- 'Announce failed workflow in Slack',
- 'CREATENEWVERSION',
- ['SLACK_WEBHOOK'],
- [],
-);
-const CREATENEWVERSION__CREATENEWVERSION__STEP_MOCKS = [
- CREATENEWVERSION__CREATENEWVERSION__RUN_TURNSTYLE__STEP_MOCK,
- CREATENEWVERSION__CREATENEWVERSION__CHECK_OUT__STEP_MOCK,
- CREATENEWVERSION__CREATENEWVERSION__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- CREATENEWVERSION__CREATENEWVERSION__GENERATE_VERSION__STEP_MOCK,
- CREATENEWVERSION__CREATENEWVERSION__COMMIT_NEW_VERSION__STEP_MOCK,
- CREATENEWVERSION__CREATENEWVERSION__UPDATE_MAIN_BRANCH__STEP_MOCK,
- CREATENEWVERSION__CREATENEWVERSION__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-export default {
- CREATENEWVERSION__VALIDATEACTOR__ADMIN__STEP_MOCKS,
- CREATENEWVERSION__VALIDATEACTOR__WRITER__STEP_MOCKS,
- CREATENEWVERSION__VALIDATEACTOR__NO_PERMISSION__STEP_MOCKS,
- CREATENEWVERSION__CREATENEWVERSION__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/deployBlockerMocks.ts b/workflow_tests/mocks/deployBlockerMocks.ts
deleted file mode 100644
index b60d41383a1e..000000000000
--- a/workflow_tests/mocks/deployBlockerMocks.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {StepIdentifier} from '@kie/act-js';
-import {createMockStep} from '../utils/utils';
-
-// updateChecklist
-const DEPLOYBLOCKER__UPDATECHECKLIST__STEP_MOCK = createMockStep('updateChecklist', 'Run updateChecklist', 'UPDATECHECKLIST');
-const DEPLOYBLOCKER__UPDATECHECKLIST__STEP_MOCKS = [DEPLOYBLOCKER__UPDATECHECKLIST__STEP_MOCK] as const satisfies StepIdentifier[];
-
-// deployblocker
-const DEPLOYBLOCKER__DEPLOYBLOCKER__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'DEPLOYBLOCKER');
-const DEPLOYBLOCKER__DEPLOYBLOCKER__GIVE_LABELS__STEP_MOCK = createMockStep(
- 'Give the issue/PR the Hourly, Engineering labels',
- 'Give the issue/PR the Hourly, Engineering labels',
- 'DEPLOYBLOCKER',
- [],
- ['GITHUB_TOKEN'],
-);
-const DEPLOYBLOCKER__DEPLOYBLOCKER__POST_THE_ISSUE_IN_THE_EXPENSIFY_OPEN_SOURCE_SLACK_ROOM__STEP_MOCK = createMockStep(
- 'Post the issue in the #expensify-open-source slack room',
- 'Post the issue in the expensify-open-source slack room',
- 'DEPLOYBLOCKER',
- ['status'],
- ['GITHUB_TOKEN', 'SLACK_WEBHOOK_URL'],
-);
-const DEPLOYBLOCKER__DEPLOYBLOCKER__COMMENT_ON_DEPLOY_BLOCKER__STEP_MOCK = createMockStep('Comment on deploy blocker', 'Comment on deploy blocker', 'DEPLOYBLOCKER', [], ['GITHUB_TOKEN']);
-const DEPLOYBLOCKER__DEPLOYBLOCKER__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK = createMockStep(
- 'Announce failed workflow in Slack',
- 'Announce failed workflow in Slack',
- 'DEPLOYBLOCKER',
- ['SLACK_WEBHOOK'],
- [],
-);
-const DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS = [
- DEPLOYBLOCKER__DEPLOYBLOCKER__CHECKOUT__STEP_MOCK,
- DEPLOYBLOCKER__DEPLOYBLOCKER__GIVE_LABELS__STEP_MOCK,
- DEPLOYBLOCKER__DEPLOYBLOCKER__POST_THE_ISSUE_IN_THE_EXPENSIFY_OPEN_SOURCE_SLACK_ROOM__STEP_MOCK,
- DEPLOYBLOCKER__DEPLOYBLOCKER__COMMENT_ON_DEPLOY_BLOCKER__STEP_MOCK,
- DEPLOYBLOCKER__DEPLOYBLOCKER__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-export default {DEPLOYBLOCKER__UPDATECHECKLIST__STEP_MOCKS, DEPLOYBLOCKER__DEPLOYBLOCKER__STEP_MOCKS};
diff --git a/workflow_tests/mocks/deployMocks.ts b/workflow_tests/mocks/deployMocks.ts
deleted file mode 100644
index 1fe5071133d7..000000000000
--- a/workflow_tests/mocks/deployMocks.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {StepIdentifier} from '@kie/act-js';
-import {createMockStep} from '../utils/utils';
-
-const DEPLOY_STAGING__CHECKOUT__STEP_MOCK = createMockStep('Checkout staging branch', 'Checking out staging branch', 'DEPLOY_STAGING', ['ref', 'token']);
-const DEPLOY_STAGING__SETUP_GIT__STEP_MOCK = createMockStep('Setup git for OSBotify', 'Setting up git for OSBotify', 'DEPLOY_STAGING', [
- 'GPG_PASSPHRASE',
- 'OS_BOTIFY_APP_ID',
- 'OS_BOTIFY_PRIVATE_KEY',
-]);
-const DEPLOY_STAGING__TAG_VERSION__STEP_MOCK = createMockStep('Tag version', 'Tagging new version', 'DEPLOY_STAGING');
-const DEPLOY_STAGING__PUSH_TAG__STEP_MOCK = createMockStep('🚀 Push tags to trigger staging deploy 🚀', 'Pushing tag to trigger staging deploy', 'DEPLOY_STAGING');
-const DEPLOY_STAGING__WARN_DEPLOYERS__STEP_MOCK = createMockStep('Warn deployers if staging deploy failed', 'Warning deployers in slack for workflow failure', 'DEPLOY_STAGING');
-const DEPLOY_STAGING_STEP_MOCKS = [
- DEPLOY_STAGING__CHECKOUT__STEP_MOCK,
- DEPLOY_STAGING__SETUP_GIT__STEP_MOCK,
- DEPLOY_STAGING__TAG_VERSION__STEP_MOCK,
- DEPLOY_STAGING__PUSH_TAG__STEP_MOCK,
- DEPLOY_STAGING__WARN_DEPLOYERS__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-const DEPLOY_PRODUCTION__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'DEPLOY_PRODUCTION', ['ref', 'token']);
-const DEPLOY_PRODUCTION__SETUP_GIT__STEP_MOCK = createMockStep(
- 'Setup git for OSBotify',
- 'Setting up git for OSBotify',
- 'DEPLOY_PRODUCTION',
- ['GPG_PASSPHRASE', 'OS_BOTIFY_APP_ID', 'OS_BOTIFY_PRIVATE_KEY'],
- null,
- {OS_BOTIFY_API_TOKEN: 'os_botify_api_token'},
-);
-const DEPLOY_PRODUCTION__CURRENT_APP_VERSION__STEP_MOCK = createMockStep('Get current app version', 'Getting current app version', 'DEPLOY_PRODUCTION', null, null, null, {
- PRODUCTION_VERSION: '1.2.3',
-});
-const DEPLOY_PRODUCTION__CREATE_RELEASE__STEP_MOCK = createMockStep(
- '🚀 Create release to trigger production deploy 🚀',
- 'Creating release to trigger production deploy',
- 'DEPLOY_PRODUCTION',
- [],
- ['GITHUB_TOKEN'],
-);
-const DEPLOY_PRODUCTION__WARN_DEPLOYERS__STEP_MOCK = createMockStep('Warn deployers if production deploy failed', 'Warning deployers in slack for workflow failure', 'DEPLOY_STAGING');
-const DEPLOY_PRODUCTION_STEP_MOCKS = [
- DEPLOY_PRODUCTION__CHECKOUT__STEP_MOCK,
- DEPLOY_PRODUCTION__SETUP_GIT__STEP_MOCK,
- DEPLOY_PRODUCTION__CURRENT_APP_VERSION__STEP_MOCK,
- DEPLOY_PRODUCTION__CREATE_RELEASE__STEP_MOCK,
- DEPLOY_PRODUCTION__WARN_DEPLOYERS__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-export default {DEPLOY_STAGING_STEP_MOCKS, DEPLOY_PRODUCTION_STEP_MOCKS};
diff --git a/workflow_tests/mocks/failureNotifierMocks.ts b/workflow_tests/mocks/failureNotifierMocks.ts
deleted file mode 100644
index ca4009aef952..000000000000
--- a/workflow_tests/mocks/failureNotifierMocks.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-
-/* eslint-disable rulesdir/no-negated-variables */
-import {createMockStep} from '../utils/utils';
-
-// notifyfailure
-const FAILURENOTIFIER__NOTIFYFAILURE__FETCH_WORKFLOW_RUN_JOBS__STEP_MOCK = createMockStep('Fetch Workflow Run Jobs', 'Fetch Workflow Run Jobs', 'NOTIFYFAILURE', [], []);
-const FAILURENOTIFIER__NOTIFYFAILURE_FETCH_PREVIOUS_WORKFLOW_RUN__STEP_MOCK = createMockStep('Fetch Previous Workflow Run', 'Fetch Previous Workflow Run', 'NOTIFYFAILURE', [], []);
-const FAILURENOTIFIER__NOTIFYFAILURE_FETCH_PREVIOUS_WORKFLOW_RUN_JOBS__STEP_MOCK = createMockStep(
- 'Fetch Previous Workflow Run Jobs',
- 'Fetch Previous Workflow Run Jobs',
- 'NOTIFYFAILURE',
- [],
- [],
-);
-const FAILURENOTIFIER__NOTIFYFAILURE__PROCESS_EACH_FAILED_JOB__STEP_MOCK = createMockStep('Process Each Failed Job', 'Process Each Failed Job', 'NOTIFYFAILURE', [], []);
-
-const FAILURENOTIFIER__NOTIFYFAILURE__STEP_MOCKS = [
- FAILURENOTIFIER__NOTIFYFAILURE__FETCH_WORKFLOW_RUN_JOBS__STEP_MOCK,
- FAILURENOTIFIER__NOTIFYFAILURE_FETCH_PREVIOUS_WORKFLOW_RUN__STEP_MOCK,
- FAILURENOTIFIER__NOTIFYFAILURE_FETCH_PREVIOUS_WORKFLOW_RUN_JOBS__STEP_MOCK,
- FAILURENOTIFIER__NOTIFYFAILURE__PROCESS_EACH_FAILED_JOB__STEP_MOCK,
-];
-
-export default {
- FAILURENOTIFIER__NOTIFYFAILURE__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/finishReleaseCycleMocks.ts b/workflow_tests/mocks/finishReleaseCycleMocks.ts
deleted file mode 100644
index 23d81a557705..000000000000
--- a/workflow_tests/mocks/finishReleaseCycleMocks.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {StepIdentifier} from '@kie/act-js';
-import {createMockStep} from '../utils/utils';
-
-// validate
-const FINISHRELEASECYCLE__VALIDATE__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'VALIDATE', ['ref', 'token']);
-const FINISHRELEASECYCLE__VALIDATE__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK = createMockStep(
- 'Setup git for OSBotify',
- 'Setup git for OSBotify',
- 'VALIDATE',
- ['GPG_PASSPHRASE', 'OS_BOTIFY_APP_ID', 'OS_BOTIFY_PRIVATE_KEY'],
- [],
- {OS_BOTIFY_API_TOKEN: 'os_botify_api_token'},
-);
-const FINISHRELEASECYCLE__VALIDATE__VALIDATE_ACTOR_IS_DEPLOYER_TRUE__STEP_MOCK = createMockStep(
- 'Validate actor is deployer',
- 'Validating if actor is deployer',
- 'VALIDATE',
- [],
- ['GITHUB_TOKEN'],
- {IS_DEPLOYER: true},
-);
-const FINISHRELEASECYCLE__VALIDATE__VALIDATE_ACTOR_IS_DEPLOYER_FALSE__STEP_MOCK = createMockStep(
- 'Validate actor is deployer',
- 'Validating if actor is deployer',
- 'VALIDATE',
- [],
- ['GITHUB_TOKEN'],
- {IS_DEPLOYER: false},
-);
-// eslint-disable-next-line rulesdir/no-negated-variables
-const FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_NOT_A_TEAM_MEMBER__STEP_MOCK = createMockStep(
- 'Reopen and comment on issue (not a team member)',
- 'Reopening issue - not a team member',
- 'VALIDATE',
- ['GITHUB_TOKEN', 'ISSUE_NUMBER', 'COMMENT'],
- [],
-);
-const FINISHRELEASECYCLE__VALIDATE__CHECK_FOR_ANY_DEPLOY_BLOCKERS_FALSE__STEP_MOCK = createMockStep(
- 'Check for any deploy blockers',
- 'Checking for deploy blockers',
- 'VALIDATE',
- ['GITHUB_TOKEN', 'ISSUE_NUMBER'],
- [],
- {HAS_DEPLOY_BLOCKERS: false},
-);
-const FINISHRELEASECYCLE__VALIDATE__CHECK_FOR_ANY_DEPLOY_BLOCKERS_TRUE__STEP_MOCK = createMockStep(
- 'Check for any deploy blockers',
- 'Checking for deploy blockers',
- 'VALIDATE',
- ['GITHUB_TOKEN', 'ISSUE_NUMBER'],
- [],
- {HAS_DEPLOY_BLOCKERS: true},
-);
-const FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_HAS_BLOCKERS__STEP_MOCK = createMockStep(
- 'Reopen and comment on issue (has blockers)',
- 'Reopening issue - blockers',
- 'VALIDATE',
- ['GITHUB_TOKEN', 'ISSUE_NUMBER'],
- [],
-);
-const FINISHRELEASECYCLE__VALIDATE__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK = createMockStep(
- 'Announce failed workflow in Slack',
- 'Announce failed workflow in Slack',
- 'VALIDATE',
- ['SLACK_WEBHOOK'],
- [],
-);
-const FINISHRELEASECYCLE__VALIDATE__TEAM_MEMBER_NO_BLOCKERS__STEP_MOCKS = [
- FINISHRELEASECYCLE__VALIDATE__CHECKOUT__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__VALIDATE_ACTOR_IS_DEPLOYER_TRUE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_NOT_A_TEAM_MEMBER__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__CHECK_FOR_ANY_DEPLOY_BLOCKERS_FALSE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_HAS_BLOCKERS__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-const FINISHRELEASECYCLE__VALIDATE__TEAM_MEMBER_BLOCKERS__STEP_MOCKS = [
- FINISHRELEASECYCLE__VALIDATE__CHECKOUT__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__VALIDATE_ACTOR_IS_DEPLOYER_TRUE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_NOT_A_TEAM_MEMBER__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__CHECK_FOR_ANY_DEPLOY_BLOCKERS_TRUE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_HAS_BLOCKERS__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-// eslint-disable-next-line rulesdir/no-negated-variables
-const FINISHRELEASECYCLE__VALIDATE__NOT_TEAM_MEMBER_NO_BLOCKERS__STEP_MOCKS = [
- FINISHRELEASECYCLE__VALIDATE__CHECKOUT__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__VALIDATE_ACTOR_IS_DEPLOYER_FALSE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_NOT_A_TEAM_MEMBER__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__CHECK_FOR_ANY_DEPLOY_BLOCKERS_FALSE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_HAS_BLOCKERS__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-// eslint-disable-next-line rulesdir/no-negated-variables
-const FINISHRELEASECYCLE__VALIDATE__NOT_TEAM_MEMBER_BLOCKERS__STEP_MOCKS = [
- FINISHRELEASECYCLE__VALIDATE__CHECKOUT__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__VALIDATE_ACTOR_IS_DEPLOYER_FALSE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_NOT_A_TEAM_MEMBER__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__CHECK_FOR_ANY_DEPLOY_BLOCKERS_TRUE__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__REOPEN_AND_COMMENT_ON_ISSUE_HAS_BLOCKERS__STEP_MOCK,
- FINISHRELEASECYCLE__VALIDATE__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-];
-
-// updateproduction
-const FINISHRELEASECYCLE__UPDATEPRODUCTION__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'UPDATEPRODUCTION', ['ref', 'token'], []);
-const FINISHRELEASECYCLE__UPDATEPRODUCTION__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK = createMockStep(
- 'Setup git for OSBotify',
- 'Setup git for OSBotify',
- 'UPDATEPRODUCTION',
- ['GPG_PASSPHRASE'],
- [],
-);
-const FINISHRELEASECYCLE__UPDATEPRODUCTION__UPDATE_PRODUCTION_BRANCH__STEP_MOCK = createMockStep('Update production branch', 'Updating production branch', 'UPDATEPRODUCTION', [], []);
-const FINISHRELEASECYCLE__UPDATEPRODUCTION__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK = createMockStep(
- 'Announce failed workflow in Slack',
- 'Announce failed workflow in Slack',
- 'UPDATEPRODUCTION',
- ['SLACK_WEBHOOK'],
- [],
-);
-const FINISHRELEASECYCLE__UPDATEPRODUCTION__STEP_MOCKS = [
- FINISHRELEASECYCLE__UPDATEPRODUCTION__CHECKOUT__STEP_MOCK,
- FINISHRELEASECYCLE__UPDATEPRODUCTION__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- FINISHRELEASECYCLE__UPDATEPRODUCTION__UPDATE_PRODUCTION_BRANCH__STEP_MOCK,
- FINISHRELEASECYCLE__UPDATEPRODUCTION__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-// createnewpatchversion
-const FINISHRELEASECYCLE__CREATENEWPATCHVERSION__CREATE_NEW_VERSION__STEP_MOCK = createMockStep(
- 'Create new version',
- 'Creating new version',
- 'CREATENEWPATCHVERSION',
- ['SEMVER_LEVEL'],
- [],
- {NEW_VERSION: '1.2.3'},
- null,
- true,
- 'createNewVersion',
-);
-const FINISHRELEASECYCLE__CREATENEWPATCHVERSION__STEP_MOCKS = [FINISHRELEASECYCLE__CREATENEWPATCHVERSION__CREATE_NEW_VERSION__STEP_MOCK] as const satisfies StepIdentifier[];
-
-// updatestaging
-const FINISHRELEASECYCLE__UPDATESTAGING__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'UPDATESTAGING', ['ref', 'token'], []);
-const FINISHRELEASECYCLE__UPDATESTAGING__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK = createMockStep('Setup git for OSBotify', 'Setup git for OSBotify', 'UPDATESTAGING', ['GPG_PASSPHRASE'], []);
-const FINISHRELEASECYCLE__UPDATESTAGING__UPDATE_STAGING_BRANCH_TO_TRIGGER_STAGING_DEPLOY__STEP_MOCK = createMockStep(
- 'Update staging branch to trigger staging deploy',
- 'Updating staging branch',
- 'UPDATESTAGING',
- [],
- [],
-);
-const FINISHRELEASECYCLE__UPDATESTAGING__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK = createMockStep(
- 'Announce failed workflow in Slack',
- 'Announce failed workflow in Slack',
- 'UPDATESTAGING',
- ['SLACK_WEBHOOK'],
- [],
-);
-const FINISHRELEASECYCLE__UPDATESTAGING__STEP_MOCKS = [
- FINISHRELEASECYCLE__UPDATESTAGING__CHECKOUT__STEP_MOCK,
- FINISHRELEASECYCLE__UPDATESTAGING__SETUP_GIT_FOR_OSBOTIFY__STEP_MOCK,
- FINISHRELEASECYCLE__UPDATESTAGING__UPDATE_STAGING_BRANCH_TO_TRIGGER_STAGING_DEPLOY__STEP_MOCK,
- FINISHRELEASECYCLE__UPDATESTAGING__ANNOUNCE_FAILED_WORKFLOW_IN_SLACK__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-export default {
- FINISHRELEASECYCLE__VALIDATE__TEAM_MEMBER_NO_BLOCKERS__STEP_MOCKS,
- FINISHRELEASECYCLE__VALIDATE__TEAM_MEMBER_BLOCKERS__STEP_MOCKS,
- FINISHRELEASECYCLE__VALIDATE__NOT_TEAM_MEMBER_NO_BLOCKERS__STEP_MOCKS,
- FINISHRELEASECYCLE__VALIDATE__NOT_TEAM_MEMBER_BLOCKERS__STEP_MOCKS,
- FINISHRELEASECYCLE__UPDATEPRODUCTION__STEP_MOCKS,
- FINISHRELEASECYCLE__CREATENEWPATCHVERSION__STEP_MOCKS,
- FINISHRELEASECYCLE__UPDATESTAGING__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/lintMocks.ts b/workflow_tests/mocks/lintMocks.ts
deleted file mode 100644
index 27ce53afc1f4..000000000000
--- a/workflow_tests/mocks/lintMocks.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import type {StepIdentifier} from '@kie/act-js';
-import {createMockStep} from '../utils/utils';
-
-// lint
-const LINT__LINT__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'LINT', [], []);
-const LINT__LINT__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'LINT', [], []);
-const LINT__LINT__LINT_JAVASCRIPT_WITH_ESLINT__STEP_MOCK = createMockStep('Lint JavaScript and Typescript with ESLint', 'Lint JavaScript with ESLint', 'LINT', [], ['CI']);
-const LINT__LINT__VERIFY_NO_PRETTIER__STEP_MOCK = createMockStep("Verify there's no Prettier diff", 'Verify theres no Prettier diff', 'LINT');
-const LINT__LINT__RUN_UNUSED_SEARCHER__STEP_MOCK = createMockStep('Run unused style searcher', 'Run unused style searcher', 'LINT');
-const LINT__LINT__STEP_MOCKS = [
- LINT__LINT__CHECKOUT__STEP_MOCK,
- LINT__LINT__SETUP_NODE__STEP_MOCK,
- LINT__LINT__LINT_JAVASCRIPT_WITH_ESLINT__STEP_MOCK,
- LINT__LINT__VERIFY_NO_PRETTIER__STEP_MOCK,
- LINT__LINT__RUN_UNUSED_SEARCHER__STEP_MOCK,
-] as const satisfies StepIdentifier[];
-
-export default {LINT__LINT__STEP_MOCKS};
diff --git a/workflow_tests/mocks/lockDeploysMocks.ts b/workflow_tests/mocks/lockDeploysMocks.ts
deleted file mode 100644
index 138b30fbb306..000000000000
--- a/workflow_tests/mocks/lockDeploysMocks.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// lockstagingdeploys
-const LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'LOCKSTAGINGDEPLOYS', ['ref', 'token'], []);
-const LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__WAIT_FOR_STAGING_DEPLOYS_TO_FINISH__STEP_MOCK = createMockStep(
- 'Wait for staging deploys to finish',
- 'Waiting for staging deploys to finish',
- 'LOCKSTAGINGDEPLOYS',
- ['GITHUB_TOKEN'],
- [],
-);
-const LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__COMMENT_IN_STAGINGDEPLOYCASH_TO_GIVE_APPLAUSE_THE_GREEN_LIGHT_TO_BEGIN_QA__STEP_MOCK = createMockStep(
- 'Comment in StagingDeployCash to give Applause the 🟢 to begin QA',
- 'Commenting in StagingDeployCash',
- 'LOCKSTAGINGDEPLOYS',
- [],
- ['GITHUB_TOKEN'],
-);
-const LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__ANNOUNCE_FAILED_WORKFLOW__STEP_MOCK = createMockStep(
- 'Announce failed workflow',
- 'Announcing failed workflow in Slack',
- 'LOCKSTAGINGDEPLOYS',
- ['SLACK_WEBHOOK'],
- [],
-);
-const LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS = [
- LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__CHECKOUT__STEP_MOCK,
- LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__WAIT_FOR_STAGING_DEPLOYS_TO_FINISH__STEP_MOCK,
- LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__COMMENT_IN_STAGINGDEPLOYCASH_TO_GIVE_APPLAUSE_THE_GREEN_LIGHT_TO_BEGIN_QA__STEP_MOCK,
- LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__ANNOUNCE_FAILED_WORKFLOW__STEP_MOCK,
-];
-
-export default {
- LOCKDEPLOYS__LOCKSTAGINGDEPLOYS__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/platformDeployMocks.ts b/workflow_tests/mocks/platformDeployMocks.ts
deleted file mode 100644
index 3aae07ec1c5a..000000000000
--- a/workflow_tests/mocks/platformDeployMocks.ts
+++ /dev/null
@@ -1,286 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// validateActor
-const PLATFORM_DEPLOY__VALIDATE_ACTOR__CHECK_USER_DEPLOYER__TEAM_MEMBER__STEP_MOCK = createMockStep(
- 'Check if user is deployer',
- 'Checking if the user is a deployer',
- 'VALIDATE_ACTOR',
- [],
- ['GITHUB_TOKEN'],
- {IS_DEPLOYER: true},
-);
-const PLATFORM_DEPLOY__VALIDATE_ACTOR__CHECK_USER_DEPLOYER__OUTSIDER__STEP_MOCK = createMockStep(
- 'Check if user is deployer',
- 'Checking if the user is a deployer',
- 'VALIDATE_ACTOR',
- [],
- ['GITHUB_TOKEN'],
- {IS_DEPLOYER: false},
-);
-const PLATFORM_DEPLOY__VALIDATE_ACTOR__TEAM_MEMBER__STEP_MOCKS = [PLATFORM_DEPLOY__VALIDATE_ACTOR__CHECK_USER_DEPLOYER__TEAM_MEMBER__STEP_MOCK];
-const PLATFORM_DEPLOY__VALIDATE_ACTOR__OUTSIDER__STEP_MOCKS = [PLATFORM_DEPLOY__VALIDATE_ACTOR__CHECK_USER_DEPLOYER__OUTSIDER__STEP_MOCK];
-
-// deployChecklist
-const PLATFORM_DEPLOY__DEPLOY_CHECKLIST__STEP_MOCK = createMockStep('deployChecklist', 'Run deployChecklist', 'DEPLOY_CHECKLIST');
-const PLATFORM_DEPLOY__DEPLOY_CHECKLIST__STEP_MOCKS = [PLATFORM_DEPLOY__DEPLOY_CHECKLIST__STEP_MOCK];
-
-// android
-const PLATFORM_DEPLOY__ANDROID__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'ANDROID');
-const PLATFORM_DEPLOY__ANDROID__CONFIGURE_MAPBOX_SDK__STEP_MOCK = createMockStep('Configure MapBox SDK', 'Configure MapBox SDK', 'ANDROID');
-const PLATFORM_DEPLOY__ANDROID__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setting up Node', 'ANDROID');
-const PLATFORM_DEPLOY__ANDROID__SETUP_JAVA__STEP_MOCK = createMockStep('Setup Java', 'Setup Java', 'ANDROID', ['distribution', 'java-version'], []);
-const PLATFORM_DEPLOY__ANDROID__SETUP_RUBY__STEP_MOCK = createMockStep('Setup Ruby', 'Setting up Ruby', 'ANDROID', ['ruby-version', 'bundler-cache']);
-const PLATFORM_DEPLOY__ANDROID__DECRYPT_KEYSTORE__STEP_MOCK = createMockStep('Decrypt keystore', 'Decrypting keystore', 'ANDROID', null, ['LARGE_SECRET_PASSPHRASE']);
-const PLATFORM_DEPLOY__ANDROID__DECRYPT_JSON_KEY__STEP_MOCK = createMockStep('Decrypt json key', 'Decrypting JSON key', 'ANDROID', null, ['LARGE_SECRET_PASSPHRASE']);
-const PLATFORM_DEPLOY__ANDROID__SET_VERSION__STEP_MOCK = createMockStep('Set version in ENV', 'Setting version in ENV', 'ANDROID', null, null, null, {VERSION_CODE: '1.2.3'});
-const PLATFORM_DEPLOY__ANDROID__FASTLANE__STEP_MOCK = createMockStep('Run Fastlane', 'Running Fastlane', 'ANDROID', null, [
- 'RUBYOPT',
- 'MYAPP_UPLOAD_STORE_PASSWORD',
- 'MYAPP_UPLOAD_KEY_PASSWORD',
- 'VERSION',
-]);
-const PLATFORM_DEPLOY__ANDROID__ARCHIVE_SOURCEMAPS__STEP_MOCK = createMockStep('Archive Android sourcemaps', 'Archiving Android sourcemaps', 'ANDROID', ['name', 'path']);
-const PLATFORM_DEPLOY__ANDROID__UPLOAD_TO_GITHUB_ARTIFACTS__STEP_MOCK = createMockStep('Upload Android build to GitHub artifacts', 'Uploading Android build to GitHub artifacts', 'ANDROID', [
- 'name',
- 'path',
-]);
-const PLATFORM_DEPLOY__ANDROID__UPLOAD_TO_BROWSER_STACK__STEP_MOCK = createMockStep('Upload Android build to Browser Stack', 'Uploading Android build to Browser Stack', 'ANDROID', null, [
- 'BROWSERSTACK',
-]);
-const PLATFORM_DEPLOY__ANDROID__UPLOAD_TO_GH_RELEASE__STEP_MOCK = createMockStep('Upload Android build to GitHub Release', 'Uploading Android build to GitHub Release', 'ANDROID', null, [
- 'GITHUB_TOKEN',
-]);
-const PLATFORM_DEPLOY__ANDROID__WARN_DEPLOYERS__STEP_MOCK = createMockStep(
- 'Warn deployers if Android production deploy failed',
- 'Warning deployers of failed production deploy',
- 'ANDROID',
- ['status'],
- ['GITHUB_TOKEN', 'SLACK_WEBHOOK_URL'],
-);
-const PLATFORM_DEPLOY__ANDROID__STEP_MOCKS = [
- PLATFORM_DEPLOY__ANDROID__CHECKOUT__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__CONFIGURE_MAPBOX_SDK__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__SETUP_NODE__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__SETUP_JAVA__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__SETUP_RUBY__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__DECRYPT_KEYSTORE__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__DECRYPT_JSON_KEY__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__SET_VERSION__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__FASTLANE__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__ARCHIVE_SOURCEMAPS__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__UPLOAD_TO_GITHUB_ARTIFACTS__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__UPLOAD_TO_BROWSER_STACK__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__UPLOAD_TO_GH_RELEASE__STEP_MOCK,
- PLATFORM_DEPLOY__ANDROID__WARN_DEPLOYERS__STEP_MOCK,
-];
-
-// desktop
-const PLATFORM_DEPLOY__DESKTOP__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'DESKTOP');
-const PLATFORM_DEPLOY__DESKTOP__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setting up Node', 'DESKTOP');
-const PLATFORM_DEPLOY__DESKTOP__DECRYPT_ID__STEP_MOCK = createMockStep('Decrypt Developer ID Certificate', 'Decrypting developer id certificate', 'DESKTOP', null, [
- 'DEVELOPER_ID_SECRET_PASSPHRASE',
-]);
-const PLATFORM_DEPLOY__DESKTOP__BUILD__STEP_MOCK = createMockStep('Build desktop app', 'Building desktop app', 'DESKTOP', null, [
- 'CSC_LINK',
- 'CSC_KEY_PASSWORD',
- 'APPLE_ID',
- 'APPLE_APP_SPECIFIC_PASSWORD',
- 'AWS_ACCESS_KEY_ID',
- 'AWS_SECRET_ACCESS_KEY',
-]);
-const PLATFORM_DEPLOY__DESKTOP__UPLOAD_WORKFLOW__STEP_MOCK = createMockStep('Upload desktop build to GitHub Workflow', 'Uploading desktop build to GitHub Workflow', 'DESKTOP', [
- 'name',
- 'path',
-]);
-const PLATFORM_DEPLOY__DESKTOP__UPLOAD_GH_RELEASE__STEP_MOCK = createMockStep('Upload desktop build to GitHub Release', 'Uploading desktop build to GitHub Release', 'DESKTOP', null, [
- 'GITHUB_TOKEN',
-]);
-const PLATFORM_DEPLOY__DESKTOP__ARCHIVE_SOURCEMAPS__STEP_MOCK = createMockStep('Archive desktop sourcemaps', 'Archiving desktop sourcemaps', 'DESKTOP', ['name', 'path']);
-const PLATFORM_DEPLOY__DESKTOP__STEP_MOCKS = [
- PLATFORM_DEPLOY__DESKTOP__CHECKOUT__STEP_MOCK,
- PLATFORM_DEPLOY__DESKTOP__SETUP_NODE__STEP_MOCK,
- PLATFORM_DEPLOY__DESKTOP__DECRYPT_ID__STEP_MOCK,
- PLATFORM_DEPLOY__DESKTOP__BUILD__STEP_MOCK,
- PLATFORM_DEPLOY__DESKTOP__UPLOAD_WORKFLOW__STEP_MOCK,
- PLATFORM_DEPLOY__DESKTOP__UPLOAD_GH_RELEASE__STEP_MOCK,
- PLATFORM_DEPLOY__DESKTOP__ARCHIVE_SOURCEMAPS__STEP_MOCK,
-];
-
-// ios
-const PLATFORM_DEPLOY__IOS__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'IOS');
-const PLATFORM_DEPLOY__IOS__CONFIGURE_MAPBOX_SDK__STEP_MOCK = createMockStep('Configure MapBox SDK', 'Configure MapBox SDK', 'IOS');
-const PLATFORM_DEPLOY__IOS__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setting up Node', 'IOS');
-const PLATFORM_DEPLOY__IOS__SETUP_RUBY__STEP_MOCK = createMockStep('Setup Ruby', 'Setting up Ruby', 'IOS', ['ruby-version', 'bundler-cache']);
-const PLATFORM_DEPLOY__IOS__CACHE_POD_DEPENDENCIES__STEP_MOCK = createMockStep('Cache Pod dependencies', 'Cache Pod dependencies', 'IOS', ['path', 'key'], [], {
- 'cache-hit': false,
-});
-const PLATFORM_DEPLOY__IOS__COMPARE_PODFILE_AND_MANIFEST__STEP_MOCK = createMockStep('Compare Podfile.lock and Manifest.lock', 'Compare Podfile.lock and Manifest.lock', 'IOS', [], [], {
- IS_PODFILE_SAME_AS_MANIFEST: false,
-});
-const PLATFORM_DEPLOY__IOS__COCOAPODS__STEP_MOCK = createMockStep('Install cocoapods', 'Installing cocoapods', 'IOS', ['timeout_minutes', 'max_attempts', 'command']);
-const PLATFORM_DEPLOY__IOS__DECRYPT_APPSTORE_PROFILE__STEP_MOCK = createMockStep('Decrypt AppStore profile', 'Decrypting profile', 'IOS', null, ['LARGE_SECRET_PASSPHRASE']);
-const PLATFORM_DEPLOY__IOS__DECRYPT_APPSTORE_NSE_PROFILE__STEP_MOCK = createMockStep('Decrypt AppStore Notification Service profile', 'Decrypting profile', 'IOS', null, [
- 'LARGE_SECRET_PASSPHRASE',
-]);
-const PLATFORM_DEPLOY__IOS__DECRYPT_CERTIFICATE__STEP_MOCK = createMockStep('Decrypt certificate', 'Decrypting certificate', 'IOS', null, ['LARGE_SECRET_PASSPHRASE']);
-const PLATFORM_DEPLOY__IOS__DECRYPT_APP_STORE_API_KEY__STEP_MOCK = createMockStep('Decrypt App Store Connect API key', 'Decrypting App Store API key', 'IOS', null, [
- 'LARGE_SECRET_PASSPHRASE',
-]);
-const PLATFORM_DEPLOY__IOS__SET_VERSION__STEP_MOCK = createMockStep('Set iOS version in ENV', 'Setting iOS version', 'IOS', null, null, null, {IOS_VERSION: '1.2.3'});
-const PLATFORM_DEPLOY__IOS__FASTLANE__STEP_MOCK = createMockStep('Run Fastlane', 'Running Fastlane', 'IOS', null, [
- 'APPLE_CONTACT_EMAIL',
- 'APPLE_CONTACT_PHONE',
- 'APPLE_DEMO_EMAIL',
- 'APPLE_DEMO_PASSWORD',
- 'VERSION',
-]);
-const PLATFORM_DEPLOY__IOS__ARCHIVE_SOURCEMAPS__STEP_MOCK = createMockStep('Archive iOS sourcemaps', 'Archiving sourcemaps', 'IOS', ['name', 'path']);
-const PLATFORM_DEPLOY__IOS__UPLOAD_TO_GITHUB_ARTIFACTS__STEP_MOCK = createMockStep('Upload iOS build to GitHub artifacts', 'Uploading iOS build to GitHub artifacts', 'IOS', [
- 'name',
- 'path',
-]);
-const PLATFORM_DEPLOY__IOS__UPLOAD_BROWSERSTACK__STEP_MOCK = createMockStep('Upload iOS build to Browser Stack', 'Uploading build to Browser Stack', 'IOS', null, ['BROWSERSTACK']);
-const PLATFORM_DEPLOY__IOS__UPLOAD_TO_GH_RELEASE__STEP_MOCK = createMockStep('Upload iOS build to GitHub Release', 'Uploading iOS build to GitHub Release', 'IOS', null, ['GITHUB_TOKEN']);
-const PLATFORM_DEPLOY__IOS__WARN_FAIL__STEP_MOCK = createMockStep(
- 'Warn deployers if iOS production deploy failed',
- 'Warning developers of failed deploy',
- 'IOS',
- ['status'],
- ['GITHUB_TOKEN', 'SLACK_WEBHOOK_URL'],
-);
-const PLATFORM_DEPLOY__IOS__STEP_MOCKS = [
- PLATFORM_DEPLOY__IOS__CHECKOUT__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__CONFIGURE_MAPBOX_SDK__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__SETUP_NODE__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__SETUP_RUBY__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__CACHE_POD_DEPENDENCIES__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__COMPARE_PODFILE_AND_MANIFEST__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__COCOAPODS__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__DECRYPT_APPSTORE_PROFILE__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__DECRYPT_APPSTORE_NSE_PROFILE__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__DECRYPT_CERTIFICATE__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__DECRYPT_APP_STORE_API_KEY__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__SET_VERSION__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__FASTLANE__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__ARCHIVE_SOURCEMAPS__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__UPLOAD_TO_GITHUB_ARTIFACTS__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__UPLOAD_BROWSERSTACK__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__UPLOAD_TO_GH_RELEASE__STEP_MOCK,
- PLATFORM_DEPLOY__IOS__WARN_FAIL__STEP_MOCK,
-];
-
-// web
-const PLATFORM_DEPLOY__WEB__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'WEB');
-const PLATFORM_DEPLOY__WEB__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setting up Node', 'WEB');
-const PLATFORM_DEPLOY__WEB__CLOUDFLARE__STEP_MOCK = createMockStep('Setup Cloudflare CLI', 'Setting up Cloudflare CLI', 'WEB');
-const PLATFORM_DEPLOY__WEB__AWS_CREDENTIALS__STEP_MOCK = createMockStep('Configure AWS Credentials', 'Configuring AWS credentials', 'WEB', [
- 'aws-access-key-id',
- 'aws-secret-access-key',
- 'aws-region',
-]);
-const PLATFORM_DEPLOY__WEB__BUILD__STEP_MOCK = createMockStep('Build web', 'Building web', 'WEB');
-const PLATFORM_DEPLOY__WEB__BUILD_STORYBOOK_DOCS__STEP_MOCK = createMockStep('Build storybook docs', 'Build storybook docs', 'WEB');
-const PLATFORM_DEPLOY__WEB__DEPLOY_S3__STEP_MOCK = createMockStep('Deploy to S3', 'Deploying to S3', 'WEB');
-const PLATFORM_DEPLOY__WEB__PURGE_CLOUDFLARE_CACHE__STEP_MOCK = createMockStep('Purge Cloudflare cache', 'Purging Cloudflare cache', 'WEB', null, ['CF_API_KEY']);
-const PLATFORM_DEPLOY__WEB__VERIFY_STAGING_DEPLOY = createMockStep('Verify staging deploy', 'Verifying staging deploy', 'WEB');
-const PLATFORM_DEPLOY__WEB__VERIFY_PROD_DEPLOY = createMockStep('Verify production deploy', 'Verifying production deploy', 'WEB');
-const PLATFORM_DEPLOY__WEB__UPlOAD_TO_GH_ARTIFACTS__STEP_MOCK = createMockStep('Upload web build to GitHub artifacts', 'Uploading web build to GitHub artifacts', 'WEB');
-const PLATFORM_DEPLOY__WEB__UPLOAD_TO_GH_RELEASE__STEP_MOCK = createMockStep('Upload web build to GitHub Release', 'Uploading web build to GitHub Release', 'WEB', null, ['GITHUB_TOKEN']);
-const PLATFORM_DEPLOY__WEB__ARCHIVE_SOURCEMAPS__STEP_MOCK = createMockStep('Archive web sourcemaps', 'Archiving web sourcemaps', 'WEB', ['name', 'path']);
-const PLATFORM_DEPLOY__WEB__STEP_MOCKS = [
- PLATFORM_DEPLOY__WEB__CHECKOUT__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__SETUP_NODE__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__CLOUDFLARE__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__AWS_CREDENTIALS__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__BUILD__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__BUILD_STORYBOOK_DOCS__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__DEPLOY_S3__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__ARCHIVE_SOURCEMAPS__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__PURGE_CLOUDFLARE_CACHE__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__VERIFY_STAGING_DEPLOY,
- PLATFORM_DEPLOY__WEB__VERIFY_PROD_DEPLOY,
- PLATFORM_DEPLOY__WEB__UPlOAD_TO_GH_ARTIFACTS__STEP_MOCK,
- PLATFORM_DEPLOY__WEB__UPLOAD_TO_GH_RELEASE__STEP_MOCK,
-];
-
-// post slack message on failure
-const PLATFORM_DEPLOY__POST_SLACK_FAIL__POST_SLACK__STEP_MOCK = createMockStep('Post Slack message on failure', 'Posting Slack message on platform deploy failure', 'POST_SLACK_FAIL', [
- 'SLACK_WEBHOOK',
-]);
-const PLATFORM_DEPLOY__POST_SLACK_FAIL__STEP_MOCKS = [PLATFORM_DEPLOY__POST_SLACK_FAIL__POST_SLACK__STEP_MOCK];
-
-// post slack message on success
-const PLATFORM_DEPLOY__POST_SLACK_SUCCESS__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'POST_SLACK_SUCCESS');
-const PLATFORM_DEPLOY__POST_SLACK_SUCCESS__SET_VERSION__STEP_MOCK = createMockStep('Set version', 'Setting version', 'POST_SLACK_SUCCESS', null, null, null, {VERSION: '1.2.3'});
-const PLATFORM_DEPLOY__POST_SLACK_SUCCESS__ANNOUNCE_CHANNEL__STEP_MOCK = createMockStep(
- 'Announces the deploy in the #announce Slack room',
- 'Posting message to \\#announce channel',
- 'POST_SLACK_SUCCESS',
- ['status'],
- ['GITHUB_TOKEN', 'SLACK_WEBHOOK_URL'],
-);
-const PLATFORM_DEPLOY__POST_SLACK_SUCCESS__DEPLOYER_CHANNEL__STEP_MOCK = createMockStep(
- 'Announces the deploy in the #deployer Slack room',
- 'Posting message to \\#deployer channel',
- 'POST_SLACK_SUCCESS',
- ['status'],
- ['GITHUB_TOKEN', 'SLACK_WEBHOOK_URL'],
-);
-const PLATFORM_DEPLOY__POST_SLACK_SUCCESS__EXPENSIFY_CHANNEL__STEP_MOCK = createMockStep(
- 'Announces a production deploy in the #expensify-open-source Slack room',
- 'Posting message to \\#expensify-open-source channel',
- 'POST_SLACK_SUCCESS',
- ['status'],
- ['GITHUB_TOKEN', 'SLACK_WEBHOOK_URL'],
-);
-const PLATFORM_DEPLOY__POST_SLACK_SUCCESS__STEP_MOCKS = [
- PLATFORM_DEPLOY__POST_SLACK_SUCCESS__CHECKOUT__STEP_MOCK,
- PLATFORM_DEPLOY__POST_SLACK_SUCCESS__SET_VERSION__STEP_MOCK,
- PLATFORM_DEPLOY__POST_SLACK_SUCCESS__ANNOUNCE_CHANNEL__STEP_MOCK,
- PLATFORM_DEPLOY__POST_SLACK_SUCCESS__DEPLOYER_CHANNEL__STEP_MOCK,
- PLATFORM_DEPLOY__POST_SLACK_SUCCESS__EXPENSIFY_CHANNEL__STEP_MOCK,
-];
-
-// post github comment
-const PLATFORM_DEPLOY__POST_GIHUB_COMMENT__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checking out', 'POST_GITHUB_COMMENT');
-const PLATFORM_DEPLOY__POST_GIHUB_COMMENT__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setting up Node', 'POST_GITHUB_COMMENT');
-const PLATFORM_DEPLOY__POST_GIHUB_COMMENT__SET_VERSION__STEP_MOCK = createMockStep('Set version', 'Setting version', 'POST_GITHUB_COMMENT', null, null, null, {VERSION: '1.2.3'});
-const PLATFORM_DEPLOY__POST_GIHUB_COMMENT__GET_PR_LIST__STEP_MOCK = createMockStep(
- 'Get Release Pull Request List',
- 'Getting release pull request list',
- 'POST_GITHUB_COMMENT',
- ['TAG', 'GITHUB_TOKEN', 'IS_PRODUCTION_DEPLOY'],
- null,
- {PR_LIST: '[1.2.1, 1.2.2]'},
-);
-const PLATFORM_DEPLOY__POST_GIHUB_COMMENT__COMMENT__STEP_MOCK = createMockStep('Comment on issues', 'Commenting on issues', 'POST_GITHUB_COMMENT', [
- 'PR_LIST',
- 'IS_PRODUCTION_DEPLOY',
- 'DEPLOY_VERSION',
- 'GITHUB_TOKEN',
- 'ANDROID',
- 'DESKTOP',
- 'IOS',
- 'WEB',
-]);
-const PLATFORM_DEPLOY__POST_GITHUB_COMMENT__STEP_MOCKS = [
- PLATFORM_DEPLOY__POST_GIHUB_COMMENT__CHECKOUT__STEP_MOCK,
- PLATFORM_DEPLOY__POST_GIHUB_COMMENT__SETUP_NODE__STEP_MOCK,
- PLATFORM_DEPLOY__POST_GIHUB_COMMENT__SET_VERSION__STEP_MOCK,
- PLATFORM_DEPLOY__POST_GIHUB_COMMENT__GET_PR_LIST__STEP_MOCK,
- PLATFORM_DEPLOY__POST_GIHUB_COMMENT__COMMENT__STEP_MOCK,
-];
-
-export default {
- PLATFORM_DEPLOY__VALIDATE_ACTOR__TEAM_MEMBER__STEP_MOCKS,
- PLATFORM_DEPLOY__VALIDATE_ACTOR__OUTSIDER__STEP_MOCKS,
- PLATFORM_DEPLOY__ANDROID__STEP_MOCKS,
- PLATFORM_DEPLOY__DESKTOP__STEP_MOCKS,
- PLATFORM_DEPLOY__IOS__STEP_MOCKS,
- PLATFORM_DEPLOY__WEB__STEP_MOCKS,
- PLATFORM_DEPLOY__POST_SLACK_FAIL__STEP_MOCKS,
- PLATFORM_DEPLOY__POST_SLACK_SUCCESS__STEP_MOCKS,
- PLATFORM_DEPLOY__POST_GITHUB_COMMENT__STEP_MOCKS,
- PLATFORM_DEPLOY__DEPLOY_CHECKLIST__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/preDeployMocks.ts b/workflow_tests/mocks/preDeployMocks.ts
deleted file mode 100644
index 12156a690804..000000000000
--- a/workflow_tests/mocks/preDeployMocks.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// typecheck
-const TYPECHECK_WORKFLOW_MOCK_STEP = createMockStep('Run typecheck workflow', 'Running typecheck workflow', 'TYPECHECK');
-const TYPECHECK_JOB_MOCK_STEPS = [TYPECHECK_WORKFLOW_MOCK_STEP];
-
-// lint
-const LINT_WORKFLOW_MOCK_STEP = createMockStep('Run lint workflow', 'Running lint workflow', 'LINT');
-const LINT_JOB_MOCK_STEPS = [LINT_WORKFLOW_MOCK_STEP];
-
-// test
-const TEST_WORKFLOW_MOCK_STEP = createMockStep('Run test workflow', 'Running test workflow', 'TEST');
-const TEST_JOB_MOCK_STEPS = [TEST_WORKFLOW_MOCK_STEP];
-
-// confirm_passing_build
-const ANNOUNCE_IN_SLACK_MOCK_STEP = createMockStep('Announce failed workflow in Slack', 'Announcing failed workflow in slack', 'CONFIRM_PASSING_BUILD', ['SLACK_WEBHOOK']);
-const CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS = [
- ANNOUNCE_IN_SLACK_MOCK_STEP,
-
- // 2nd step runs normally
-];
-
-// choose_deploy_actions
-const GET_MERGED_PULL_REQUEST_MOCK_STEP__CHOOSE_DEPLOY = createMockStep('Get merged pull request', 'Getting merged pull request', 'CHOOSE_DEPLOY_ACTIONS', ['github_token'], null, {
- number: '123',
- labels: '[]',
-});
-const CHECK_IF_STAGINGDEPLOYCASH_IS_LOCKED_MOCK_STEP__LOCKED = createMockStep(
- 'Check if StagingDeployCash is locked',
- 'Checking StagingDeployCash',
- 'CHOOSE_DEPLOY_ACTIONS',
- ['GITHUB_TOKEN'],
- null,
- {IS_LOCKED: true},
-);
-const CHECK_IF_STAGINGDEPLOYCASH_IS_LOCKED_MOCK_STEP__UNLOCKED = createMockStep(
- 'Check if StagingDeployCash is locked',
- 'Checking StagingDeployCash',
- 'CHOOSE_DEPLOY_ACTIONS',
- ['GITHUB_TOKEN'],
- null,
- {IS_LOCKED: false},
-);
-const CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_LOCKED = [
- GET_MERGED_PULL_REQUEST_MOCK_STEP__CHOOSE_DEPLOY,
- CHECK_IF_STAGINGDEPLOYCASH_IS_LOCKED_MOCK_STEP__LOCKED,
-
- // step 3 runs normally
-];
-const CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED = [
- GET_MERGED_PULL_REQUEST_MOCK_STEP__CHOOSE_DEPLOY,
- CHECK_IF_STAGINGDEPLOYCASH_IS_LOCKED_MOCK_STEP__UNLOCKED,
-
- // step 3 runs normally
-];
-
-// skip_deploy
-const COMMENT_ON_DEFERRED_PR_MOCK_STEP = createMockStep('Comment on deferred PR', 'Skipping deploy', 'SKIP_DEPLOY', ['github_token', 'number', 'body']);
-const SKIP_DEPLOY_JOB_MOCK_STEPS = [COMMENT_ON_DEFERRED_PR_MOCK_STEP];
-
-// create_new_version
-const CREATE_NEW_VERSION_MOCK_STEP = createMockStep('Create new version', 'Creating new version', 'CREATE_NEW_VERSION', null, null, {NEW_VERSION: '1.2.3'}, null, true, 'createNewVersion');
-const CREATE_NEW_VERSION_JOB_MOCK_STEPS = [CREATE_NEW_VERSION_MOCK_STEP];
-
-// update_staging
-const RUN_TURNSTYLE_MOCK_STEP = createMockStep('Run turnstyle', 'Running turnstyle', 'UPDATE_STAGING', ['poll-interval-seconds'], ['GITHUB_TOKEN']);
-const CHECKOUT_MAIN_MOCK_STEP = createMockStep('Checkout main', 'Checkout main', 'UPDATE_STAGING', ['ref', 'token']);
-const SETUP_GIT_FOR_OSBOTIFY_MOCK_STEP = createMockStep('Setup Git for OSBotify', 'Setup Git for OSBotify', 'UPDATE_STAGING', ['GPG_PASSPHRASE']);
-const UPDATE_STAGING_BRANCH_FROM_MAIN_MOCK_STEP = createMockStep('Update staging branch from main', 'Update staging branch from main', 'UPDATE_STAGING');
-const ANNOUNCE_FAILED_WORKFLOW_IN_SLACK_MOCK_STEP = createMockStep('Announce failed workflow in Slack', 'Announcing failed workflow in Slack', 'UPDATE_STAGING', ['SLACK_WEBHOOK']);
-const UPDATE_STAGING_JOB_MOCK_STEPS = [
- RUN_TURNSTYLE_MOCK_STEP,
- CHECKOUT_MAIN_MOCK_STEP,
- SETUP_GIT_FOR_OSBOTIFY_MOCK_STEP,
- UPDATE_STAGING_BRANCH_FROM_MAIN_MOCK_STEP,
- ANNOUNCE_FAILED_WORKFLOW_IN_SLACK_MOCK_STEP,
-];
-
-const PREDEPLOY__E2EPERFORMANCETESTS__PERFORM_E2E_TESTS__MOCK_STEP = createMockStep('Perform E2E tests', 'Perform E2E tests', 'E2EPERFORMANCETESTS');
-const PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS = [PREDEPLOY__E2EPERFORMANCETESTS__PERFORM_E2E_TESTS__MOCK_STEP];
-
-export default {
- TYPECHECK_JOB_MOCK_STEPS,
- LINT_JOB_MOCK_STEPS,
- TEST_JOB_MOCK_STEPS,
- CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_LOCKED,
- CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- SKIP_DEPLOY_JOB_MOCK_STEPS,
- CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- UPDATE_STAGING_JOB_MOCK_STEPS,
- PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
-};
diff --git a/workflow_tests/mocks/reviewerChecklistMocks.ts b/workflow_tests/mocks/reviewerChecklistMocks.ts
deleted file mode 100644
index 8a70c0c71597..000000000000
--- a/workflow_tests/mocks/reviewerChecklistMocks.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// checklist
-const REVIEWERCHECKLIST__CHECKLIST__REVIEWERCHECKLIST_JS__STEP_MOCK = createMockStep('reviewerChecklist.js', 'reviewerChecklist.js', 'CHECKLIST', ['GITHUB_TOKEN'], []);
-const REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS = [REVIEWERCHECKLIST__CHECKLIST__REVIEWERCHECKLIST_JS__STEP_MOCK];
-
-export default {
- REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/testBuildMocks.ts b/workflow_tests/mocks/testBuildMocks.ts
deleted file mode 100644
index 643e57ddf675..000000000000
--- a/workflow_tests/mocks/testBuildMocks.ts
+++ /dev/null
@@ -1,261 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// validateactor
-const TESTBUILD__VALIDATEACTOR__IS_TEAM_MEMBER__TRUE__STEP_MOCK = createMockStep('Is Expensify employee', 'Is Expensify employee', 'VALIDATEACTOR', [], ['GITHUB_TOKEN'], {
- IS_EXPENSIFY_EMPLOYEE: true,
-});
-const TESTBUILD__VALIDATEACTOR__IS_TEAM_MEMBER__FALSE__STEP_MOCK = createMockStep('Is Expensify employee', 'Is Expensify employee', 'VALIDATEACTOR', [], ['GITHUB_TOKEN'], {
- IS_EXPENSIFY_EMPLOYEE: false,
-});
-const TESTBUILD__VALIDATEACTOR__SET_HAS_READY_TO_BUILD_LABEL_FLAG__TRUE__STEP_MOCK = createMockStep(
- 'Set HAS_READY_TO_BUILD_LABEL flag',
- 'Set HAS_READY_TO_BUILD_LABEL flag',
- 'VALIDATEACTOR',
- [],
- ['PULL_REQUEST_NUMBER', 'GITHUB_TOKEN'],
- {HAS_READY_TO_BUILD_LABEL: true},
-);
-const TESTBUILD__VALIDATEACTOR__SET_HAS_READY_TO_BUILD_LABEL_FLAG__FALSE__STEP_MOCK = createMockStep(
- 'Set HAS_READY_TO_BUILD_LABEL flag',
- 'Set HAS_READY_TO_BUILD_LABEL flag',
- 'VALIDATEACTOR',
- [],
- ['PULL_REQUEST_NUMBER', 'GITHUB_TOKEN'],
- {HAS_READY_TO_BUILD_LABEL: false},
-);
-const TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS = [
- TESTBUILD__VALIDATEACTOR__IS_TEAM_MEMBER__TRUE__STEP_MOCK,
- TESTBUILD__VALIDATEACTOR__SET_HAS_READY_TO_BUILD_LABEL_FLAG__TRUE__STEP_MOCK,
-];
-const TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_NO_FLAG__STEP_MOCKS = [
- TESTBUILD__VALIDATEACTOR__IS_TEAM_MEMBER__TRUE__STEP_MOCK,
- TESTBUILD__VALIDATEACTOR__SET_HAS_READY_TO_BUILD_LABEL_FLAG__FALSE__STEP_MOCK,
-];
-const TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_HAS_FLAG__STEP_MOCKS = [
- TESTBUILD__VALIDATEACTOR__IS_TEAM_MEMBER__FALSE__STEP_MOCK,
- TESTBUILD__VALIDATEACTOR__SET_HAS_READY_TO_BUILD_LABEL_FLAG__TRUE__STEP_MOCK,
-];
-const TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_NO_FLAG__STEP_MOCKS = [
- TESTBUILD__VALIDATEACTOR__IS_TEAM_MEMBER__FALSE__STEP_MOCK,
- TESTBUILD__VALIDATEACTOR__SET_HAS_READY_TO_BUILD_LABEL_FLAG__FALSE__STEP_MOCK,
-];
-
-// getbranchref
-const TESTBUILD__GETBRANCHREF__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'GETBRANCHREF', [], []);
-const TESTBUILD__GETBRANCHREF__CHECK_IF_PULL_REQUEST_NUMBER_IS_CORRECT__STEP_MOCK = createMockStep(
- 'Check if pull request number is correct',
- 'Check if pull request number is correct',
- 'GETBRANCHREF',
- [],
- ['GITHUB_TOKEN'],
- {REF: 'test-ref'},
-);
-const TESTBUILD__GETBRANCHREF__STEP_MOCKS = [TESTBUILD__GETBRANCHREF__CHECKOUT__STEP_MOCK, TESTBUILD__GETBRANCHREF__CHECK_IF_PULL_REQUEST_NUMBER_IS_CORRECT__STEP_MOCK];
-
-// android
-const TESTBUILD__ANDROID__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'ANDROID', ['ref'], []);
-const TESTBUILD__ANDROID__CREATE_ENV_ADHOC__STEP_MOCK = createMockStep(
- 'Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it',
- 'Creating .env.adhoc file based on staging',
- 'ANDROID',
- [],
- [],
-);
-const TESTBUILD__ANDROID__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'ANDROID', [], []);
-const TESTBUILD__ANDROID__SETUP_JAVA__STEP_MOCK = createMockStep('Setup Java', 'Setup Java', 'ANDROID', ['distribution', 'java-version'], []);
-const TESTBUILD__ANDROID__SETUP_RUBY__STEP_MOCK = createMockStep('Setup Ruby', 'Setup Ruby', 'ANDROID', ['ruby-version', 'bundler-cache'], []);
-const TESTBUILD__ANDROID__DECRYPT_KEYSTORE__STEP_MOCK = createMockStep('Decrypt keystore', 'Decrypt keystore', 'ANDROID', [], ['LARGE_SECRET_PASSPHRASE']);
-const TESTBUILD__ANDROID__DECRYPT_JSON_KEY__STEP_MOCK = createMockStep('Decrypt json key', 'Decrypt json key', 'ANDROID', [], ['LARGE_SECRET_PASSPHRASE']);
-const TESTBUILD__ANDROID__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK = createMockStep(
- 'Configure AWS Credentials',
- 'Configure AWS Credentials',
- 'ANDROID',
- ['aws-access-key-id', 'aws-secret-access-key', 'aws-region'],
- [],
-);
-const TESTBUILD__ANDROID__CONFIGURE_MAPBOX_SDK__STEP_MOCK = createMockStep('Configure MapBox SDK', 'Configure MapBox SDK', 'ANDROID');
-const TESTBUILD__ANDROID__RUN_FASTLANE_BETA_TEST__STEP_MOCK = createMockStep(
- 'Run Fastlane beta test',
- 'Run Fastlane beta test',
- 'ANDROID',
- [],
- ['S3_ACCESS_KEY', 'S3_SECRET_ACCESS_KEY', 'S3_BUCKET', 'S3_REGION', 'MYAPP_UPLOAD_STORE_PASSWORD', 'MYAPP_UPLOAD_KEY_PASSWORD'],
-);
-const TESTBUILD__ANDROID__UPLOAD_ARTIFACT__STEP_MOCK = createMockStep('Upload Artifact', 'Upload Artifact', 'ANDROID', ['name', 'path'], []);
-const TESTBUILD__ANDROID__STEP_MOCKS = [
- TESTBUILD__ANDROID__CHECKOUT__STEP_MOCK,
- TESTBUILD__ANDROID__CREATE_ENV_ADHOC__STEP_MOCK,
- TESTBUILD__ANDROID__SETUP_NODE__STEP_MOCK,
- TESTBUILD__ANDROID__SETUP_JAVA__STEP_MOCK,
- TESTBUILD__ANDROID__SETUP_RUBY__STEP_MOCK,
- TESTBUILD__ANDROID__DECRYPT_KEYSTORE__STEP_MOCK,
- TESTBUILD__ANDROID__DECRYPT_JSON_KEY__STEP_MOCK,
- TESTBUILD__ANDROID__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK,
- TESTBUILD__ANDROID__CONFIGURE_MAPBOX_SDK__STEP_MOCK,
- TESTBUILD__ANDROID__RUN_FASTLANE_BETA_TEST__STEP_MOCK,
- TESTBUILD__ANDROID__UPLOAD_ARTIFACT__STEP_MOCK,
-];
-
-// ios
-const TESTBUILD__IOS__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'IOS', ['ref'], []);
-const TESTBUILD__IOS__CONFIGURE_MAPBOX_SDK__STEP_MOCK = createMockStep('Configure MapBox SDK', 'Configure MapBox SDK', 'IOS');
-const TESTBUILD__IOS__CREATE_ENV_ADHOC__STEP_MOCK = createMockStep(
- 'Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it',
- 'Creating .env.adhoc file based on staging',
- 'IOS',
- [],
- [],
-);
-const TESTBUILD__IOS__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'IOS', [], []);
-const TESTBUILD__IOS__SETUP_XCODE__STEP_MOCK = createMockStep('Setup XCode', 'Setup XCode', 'IOS', [], []);
-const TESTBUILD__IOS__SETUP_RUBY__STEP_MOCK = createMockStep('Setup Ruby', 'Setup Ruby', 'IOS', ['ruby-version', 'bundler-cache'], []);
-const TESTBUILD__IOS__CACHE_POD_DEPENDENCIES__STEP_MOCK = createMockStep('Cache Pod dependencies', 'Cache Pod dependencies', 'IOS', ['path', 'key'], [], {
- 'cache-hit': false,
-});
-const TESTBUILD__IOS__COMPARE_PODFILE_AND_MANIFEST__STEP_MOCK = createMockStep('Compare Podfile.lock and Manifest.lock', 'Compare Podfile.lock and Manifest.lock', 'IOS', [], [], {
- IS_PODFILE_SAME_AS_MANIFEST: false,
-});
-const TESTBUILD__IOS__INSTALL_COCOAPODS__STEP_MOCK = createMockStep('Install cocoapods', 'Install cocoapods', 'IOS', ['timeout_minutes', 'max_attempts', 'command'], []);
-const TESTBUILD__IOS__DECRYPT_ADHOC_PROFILE__STEP_MOCK = createMockStep('Decrypt AdHoc profile', 'Decrypt AdHoc profile', 'IOS', [], ['LARGE_SECRET_PASSPHRASE']);
-const TESTBUILD__IOS__DECRYPT_ADHOC_NSE_PROFILE__STEP_MOCK = createMockStep(
- 'Decrypt AdHoc Notification Service profile',
- 'Decrypt AdHoc Notification Service profile',
- 'IOS',
- [],
- ['LARGE_SECRET_PASSPHRASE'],
-);
-const TESTBUILD__IOS__DECRYPT_CERTIFICATE__STEP_MOCK = createMockStep('Decrypt certificate', 'Decrypt certificate', 'IOS', [], ['LARGE_SECRET_PASSPHRASE']);
-const TESTBUILD__IOS__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK = createMockStep(
- 'Configure AWS Credentials',
- 'Configure AWS Credentials',
- 'IOS',
- ['aws-access-key-id', 'aws-secret-access-key', 'aws-region'],
- [],
-);
-const TESTBUILD__IOS__RUN_FASTLANE__STEP_MOCK = createMockStep('Run Fastlane', 'Run Fastlane', 'IOS', [], ['S3_ACCESS_KEY', 'S3_SECRET_ACCESS_KEY', 'S3_BUCKET', 'S3_REGION']);
-const TESTBUILD__IOS__UPLOAD_ARTIFACT__STEP_MOCK = createMockStep('Upload Artifact', 'Upload Artifact', 'IOS', ['name', 'path'], []);
-const TESTBUILD__IOS__STEP_MOCKS = [
- TESTBUILD__IOS__CHECKOUT__STEP_MOCK,
- TESTBUILD__IOS__CONFIGURE_MAPBOX_SDK__STEP_MOCK,
- TESTBUILD__IOS__CREATE_ENV_ADHOC__STEP_MOCK,
- TESTBUILD__IOS__SETUP_NODE__STEP_MOCK,
- TESTBUILD__IOS__SETUP_XCODE__STEP_MOCK,
- TESTBUILD__IOS__SETUP_RUBY__STEP_MOCK,
- TESTBUILD__IOS__CACHE_POD_DEPENDENCIES__STEP_MOCK,
- TESTBUILD__IOS__COMPARE_PODFILE_AND_MANIFEST__STEP_MOCK,
- TESTBUILD__IOS__INSTALL_COCOAPODS__STEP_MOCK,
- TESTBUILD__IOS__DECRYPT_ADHOC_PROFILE__STEP_MOCK,
- TESTBUILD__IOS__DECRYPT_ADHOC_NSE_PROFILE__STEP_MOCK,
- TESTBUILD__IOS__DECRYPT_CERTIFICATE__STEP_MOCK,
- TESTBUILD__IOS__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK,
- TESTBUILD__IOS__RUN_FASTLANE__STEP_MOCK,
- TESTBUILD__IOS__UPLOAD_ARTIFACT__STEP_MOCK,
-];
-
-// desktop
-const TESTBUILD__DESKTOP__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'DESKTOP', ['ref'], []);
-const TESTBUILD__DESKTOP__CREATE_ENV_ADHOC__STEP_MOCK = createMockStep(
- 'Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it',
- 'Creating .env.adhoc file based on staging',
- 'DESKTOP',
- [],
- [],
-);
-const TESTBUILD__DESKTOP__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'DESKTOP', [], []);
-const TESTBUILD__DESKTOP__DECRYPT_DEVELOPER_ID_CERTIFICATE__STEP_MOCK = createMockStep(
- 'Decrypt Developer ID Certificate',
- 'Decrypt Developer ID Certificate',
- 'DESKTOP',
- [],
- ['DEVELOPER_ID_SECRET_PASSPHRASE'],
-);
-const TESTBUILD__DESKTOP__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK = createMockStep(
- 'Configure AWS Credentials',
- 'Configure AWS Credentials',
- 'DESKTOP',
- ['aws-access-key-id', 'aws-secret-access-key', 'aws-region'],
- [],
-);
-const TESTBUILD__DESKTOP__BUILD_DESKTOP_APP_FOR_TESTING__STEP_MOCK = createMockStep(
- 'Build desktop app for testing',
- 'Build desktop app for testing',
- 'DESKTOP',
- [],
- ['CSC_LINK', 'CSC_KEY_PASSWORD', 'APPLE_ID', 'APPLE_APP_SPECIFIC_PASSWORD', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],
-);
-const TESTBUILD__DESKTOP__STEP_MOCKS = [
- TESTBUILD__DESKTOP__CHECKOUT__STEP_MOCK,
- TESTBUILD__DESKTOP__CREATE_ENV_ADHOC__STEP_MOCK,
- TESTBUILD__DESKTOP__SETUP_NODE__STEP_MOCK,
- TESTBUILD__DESKTOP__DECRYPT_DEVELOPER_ID_CERTIFICATE__STEP_MOCK,
- TESTBUILD__DESKTOP__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK,
- TESTBUILD__DESKTOP__BUILD_DESKTOP_APP_FOR_TESTING__STEP_MOCK,
-];
-
-// web
-const TESTBUILD__WEB__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'WEB', ['ref'], []);
-const TESTBUILD__WEB__CREATE_ENV_ADHOC__STEP_MOCK = createMockStep(
- 'Create .env.adhoc file based on staging and add PULL_REQUEST_NUMBER env to it',
- 'Creating .env.adhoc file based on staging',
- 'WEB',
- [],
- [],
-);
-const TESTBUILD__WEB__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'WEB', [], []);
-const TESTBUILD__WEB__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK = createMockStep(
- 'Configure AWS Credentials',
- 'Configure AWS Credentials',
- 'WEB',
- ['aws-access-key-id', 'aws-secret-access-key', 'aws-region'],
- [],
-);
-const TESTBUILD__WEB__BUILD_WEB_FOR_TESTING__STEP_MOCK = createMockStep('Build web for testing', 'Build web for testing', 'WEB', [], []);
-const TESTBUILD__WEB__BUILD_DOCS__STEP_MOCK = createMockStep('Build docs', 'Build docs', 'WEB', [], []);
-const TESTBUILD__WEB__DEPLOY_TO_S3_FOR_INTERNAL_TESTING__STEP_MOCK = createMockStep('Deploy to S3 for internal testing', 'Deploy to S3 for internal testing', 'WEB', [], []);
-const TESTBUILD__WEB__STEP_MOCKS = [
- TESTBUILD__WEB__CHECKOUT__STEP_MOCK,
- TESTBUILD__WEB__CREATE_ENV_ADHOC__STEP_MOCK,
- TESTBUILD__WEB__SETUP_NODE__STEP_MOCK,
- TESTBUILD__WEB__CONFIGURE_AWS_CREDENTIALS__STEP_MOCK,
- TESTBUILD__WEB__BUILD_WEB_FOR_TESTING__STEP_MOCK,
- TESTBUILD__WEB__BUILD_DOCS__STEP_MOCK,
- TESTBUILD__WEB__DEPLOY_TO_S3_FOR_INTERNAL_TESTING__STEP_MOCK,
-];
-
-// postgithubcomment
-const TESTBUILD__POSTGITHUBCOMMENT__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'POSTGITHUBCOMMENT', ['ref'], []);
-const TESTBUILD__POSTGITHUBCOMMENT__DOWNLOAD_ARTIFACT__STEP_MOCK = createMockStep('Download Artifact', 'Download Artifact', 'POSTGITHUBCOMMENT', [], []);
-const TESTBUILD__POSTGITHUBCOMMENT__READ_JSONS_WITH_ANDROID_PATHS__STEP_MOCK = createMockStep('Read JSONs with android paths', 'Read JSONs with android paths', 'POSTGITHUBCOMMENT', [], [], {
- android_path: 'http://dummy.android.link',
-});
-const TESTBUILD__POSTGITHUBCOMMENT__READ_JSONS_WITH_IOS_PATHS__STEP_MOCK = createMockStep('Read JSONs with iOS paths', 'Read JSONs with iOS paths', 'POSTGITHUBCOMMENT', [], [], {
- ios_path: 'http://dummy.ios.link',
-});
-const TESTBUILD__POSTGITHUBCOMMENT__PUBLISH_LINKS_TO_APPS_FOR_DOWNLOAD__STEP_MOCK = createMockStep(
- 'Publish links to apps for download',
- 'Publish links to apps for download',
- 'POSTGITHUBCOMMENT',
- ['PR_NUMBER', 'GITHUB_TOKEN', 'ANDROID', 'DESKTOP', 'IOS', 'WEB', 'ANDROID_LINK', 'DESKTOP_LINK', 'IOS_LINK', 'WEB_LINK'],
- [],
-);
-const TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS = [
- TESTBUILD__POSTGITHUBCOMMENT__CHECKOUT__STEP_MOCK,
- TESTBUILD__POSTGITHUBCOMMENT__DOWNLOAD_ARTIFACT__STEP_MOCK,
- TESTBUILD__POSTGITHUBCOMMENT__READ_JSONS_WITH_ANDROID_PATHS__STEP_MOCK,
- TESTBUILD__POSTGITHUBCOMMENT__READ_JSONS_WITH_IOS_PATHS__STEP_MOCK,
- TESTBUILD__POSTGITHUBCOMMENT__PUBLISH_LINKS_TO_APPS_FOR_DOWNLOAD__STEP_MOCK,
-];
-
-export default {
- TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- TESTBUILD__ANDROID__STEP_MOCKS,
- TESTBUILD__IOS__STEP_MOCKS,
- TESTBUILD__DESKTOP__STEP_MOCKS,
- TESTBUILD__WEB__STEP_MOCKS,
- TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/testMocks.ts b/workflow_tests/mocks/testMocks.ts
deleted file mode 100644
index 96bec3f0422a..000000000000
--- a/workflow_tests/mocks/testMocks.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// jest
-const TEST__JEST__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'JEST', [], []);
-const TEST__JEST__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'JEST', [], []);
-const TEST__JEST__GET_NUMBER_OF_CPU_CORES__STEP_MOCK = createMockStep('Get number of CPU cores', 'Get number of CPU cores', 'JEST', [], [], {count: 8});
-const TEST__JEST__CACHE_JEST_CACHE__STEP_MOCK = createMockStep('Cache Jest cache', 'Cache Jest cache', 'JEST', ['path', 'key'], []);
-const TEST__JEST__JEST_TESTS__STEP_MOCK = createMockStep('Jest tests', 'Jest tests', 'JEST', [], []);
-const TEST__JEST__STEP_MOCKS = [
- TEST__JEST__CHECKOUT__STEP_MOCK,
- TEST__JEST__SETUP_NODE__STEP_MOCK,
- TEST__JEST__GET_NUMBER_OF_CPU_CORES__STEP_MOCK,
- TEST__JEST__CACHE_JEST_CACHE__STEP_MOCK,
- TEST__JEST__JEST_TESTS__STEP_MOCK,
-];
-
-export default {TEST__JEST__STEP_MOCKS};
diff --git a/workflow_tests/mocks/validateGithubActionsMocks.ts b/workflow_tests/mocks/validateGithubActionsMocks.ts
deleted file mode 100644
index 2c1afba74387..000000000000
--- a/workflow_tests/mocks/validateGithubActionsMocks.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// verify
-const VALIDATEGITHUBACTIONS__VERIFY__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'VERIFY');
-const VALIDATEGITHUBACTIONS__VERIFY__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'VERIFY', [], []);
-const VALIDATEGITHUBACTIONS__VERIFY__VERIFY_JAVASCRIPT_ACTION_BUILDS__STEP_MOCK = createMockStep('Verify Javascript Action Builds', 'Verify Javascript Action Builds', 'VERIFY', [], []);
-const VALIDATEGITHUBACTIONS__VERIFY__VALIDATE_ACTIONS_AND_WORKFLOWS__STEP_MOCK = createMockStep('Validate actions and workflows', 'Validate actions and workflows', 'VERIFY', [], []);
-const VALIDATEGITHUBACTIONS__VERIFY__STEP_MOCKS = [
- VALIDATEGITHUBACTIONS__VERIFY__CHECKOUT__STEP_MOCK,
- VALIDATEGITHUBACTIONS__VERIFY__SETUP_NODE__STEP_MOCK,
- VALIDATEGITHUBACTIONS__VERIFY__VERIFY_JAVASCRIPT_ACTION_BUILDS__STEP_MOCK,
- VALIDATEGITHUBACTIONS__VERIFY__VALIDATE_ACTIONS_AND_WORKFLOWS__STEP_MOCK,
-];
-
-export default {
- VALIDATEGITHUBACTIONS__VERIFY__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/verifyPodfileMocks.ts b/workflow_tests/mocks/verifyPodfileMocks.ts
deleted file mode 100644
index 0cd7ea396dad..000000000000
--- a/workflow_tests/mocks/verifyPodfileMocks.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// verify
-const VERIFYPODFILE__VERIFY__CHECKOUT__STEP_MOCK = createMockStep('Checkout', 'Checkout', 'VERIFY');
-const VERIFYPODFILE__VERIFY__SETUP_NODE__STEP_MOCK = createMockStep('Setup Node', 'Setup Node', 'VERIFY', [], []);
-const VERIFYPODFILE__VERIFY__VERIFY_PODFILE__STEP_MOCK = createMockStep('Verify podfile', 'Verify podfile', 'VERIFY', [], []);
-const VERIFYPODFILE__VERIFY__STEP_MOCKS = [VERIFYPODFILE__VERIFY__CHECKOUT__STEP_MOCK, VERIFYPODFILE__VERIFY__SETUP_NODE__STEP_MOCK, VERIFYPODFILE__VERIFY__VERIFY_PODFILE__STEP_MOCK];
-
-export default {
- VERIFYPODFILE__VERIFY__STEP_MOCKS,
-};
diff --git a/workflow_tests/mocks/verifySignedCommitsMocks.ts b/workflow_tests/mocks/verifySignedCommitsMocks.ts
deleted file mode 100644
index 6109af183fd7..000000000000
--- a/workflow_tests/mocks/verifySignedCommitsMocks.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {createMockStep} from '../utils/utils';
-
-// verifysignedcommits
-const VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__VERIFY_SIGNED_COMMITS__STEP_MOCK = createMockStep(
- 'Verify signed commits',
- 'Verify signed commits',
- 'VERIFYSIGNEDCOMMITS',
- ['GITHUB_TOKEN'],
- [],
-);
-const VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__STEP_MOCKS = [VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__VERIFY_SIGNED_COMMITS__STEP_MOCK];
-
-export default {
- VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__STEP_MOCKS,
-};
diff --git a/workflow_tests/platformDeploy.test.ts b/workflow_tests/platformDeploy.test.ts
deleted file mode 100644
index 074154798f32..000000000000
--- a/workflow_tests/platformDeploy.test.ts
+++ /dev/null
@@ -1,303 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/platformDeployAssertions';
-import mocks from './mocks/platformDeployMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import type {MockJobs} from './utils/JobMocker';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'platformDeploy.yml'),
- dest: '.github/workflows/platformDeploy.yml',
- },
-];
-
-describe('test workflow platformDeploy', () => {
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testPlatformDeployWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- pushedBranches: [],
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
-
- describe('push', () => {
- describe('tag', () => {
- it('as team member - platform deploy executes on staging', async () => {
- const repoPath = mockGithub.repo.getPath('testPlatformDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {
- ref: 'refs/tags/1.2.3',
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ref_type: 'tag',
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ref_name: '1.2.3',
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- MYAPP_UPLOAD_STORE_PASSWORD: 'dummy_store_password',
- MYAPP_UPLOAD_KEY_PASSWORD: 'dummy_key_password',
- BROWSERSTACK: 'dummy_browserstack',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- DEVELOPER_ID_SECRET_PASSPHRASE: 'dummy_secret_passphrase',
- CSC_LINK: 'dummy_csc_link',
- CSC_KEY_PASSWORD: 'dummy_csc_key_pass',
- APPLE_ID: 'dummy_apple_id',
- APPLE_ID_PASSWORD: 'dummy_apple_pass',
- AWS_ACCESS_KEY_ID: 'dummy_aws_access_key_id',
- AWS_SECRET_ACCESS_KEY: 'dummy_aws_secret_access_key',
- APPLE_CONTACT_EMAIL: 'dummy@email.com',
- APPLE_CONTACT_PHONE: '123456789',
- APPLE_DEMO_EMAIL: 'dummy.demo@email.com',
- APPLE_DEMO_PASSWORD: 'dummy_password',
- CLOUDFLARE_TOKEN: 'dummy_cloudflare_token',
- },
- 'dummy_github_token',
- {
- AS_REPO: 'App',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- desktop: 'ubuntu-latest',
- iOS: 'ubuntu-latest',
- android: 'ubuntu-latest',
- web: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps: MockStep = {
- validateActor: mocks.PLATFORM_DEPLOY__VALIDATE_ACTOR__TEAM_MEMBER__STEP_MOCKS,
- android: mocks.PLATFORM_DEPLOY__ANDROID__STEP_MOCKS,
- desktop: mocks.PLATFORM_DEPLOY__DESKTOP__STEP_MOCKS,
- iOS: mocks.PLATFORM_DEPLOY__IOS__STEP_MOCKS,
- web: mocks.PLATFORM_DEPLOY__WEB__STEP_MOCKS,
- postSlackMessageOnFailure: mocks.PLATFORM_DEPLOY__POST_SLACK_FAIL__STEP_MOCKS,
- postSlackMessageOnSuccess: mocks.PLATFORM_DEPLOY__POST_SLACK_SUCCESS__STEP_MOCKS,
- postGithubComment: mocks.PLATFORM_DEPLOY__POST_GITHUB_COMMENT__STEP_MOCKS,
- };
- const testMockJobs: MockJobs = {
- deployChecklist: {
- steps: mocks.PLATFORM_DEPLOY__DEPLOY_CHECKLIST__STEP_MOCKS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('platformDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertVerifyActorJobExecuted(result);
- assertions.assertDeployChecklistJobExecuted(result, true);
- assertions.assertAndroidJobExecuted(result, true, false, true);
- assertions.assertDesktopJobExecuted(result, true, false);
- assertions.assertIOSJobExecuted(result, true, false, true);
- assertions.assertWebJobExecuted(result, true);
- assertions.assertPostSlackOnFailureJobExecuted(result, false);
- assertions.assertPostSlackOnSuccessJobExecuted(result, true, false);
- assertions.assertPostGithubCommentJobExecuted(result, true, false);
- });
-
- it('as OSBotify - platform deploy executes on staging', async () => {
- const repoPath = mockGithub.repo.getPath('testPlatformDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {
- ref: 'refs/tags/1.2.3',
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ref_type: 'tag',
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ref_name: '1.2.3',
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- MYAPP_UPLOAD_STORE_PASSWORD: 'dummy_store_password',
- MYAPP_UPLOAD_KEY_PASSWORD: 'dummy_key_password',
- BROWSERSTACK: 'dummy_browserstack',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- DEVELOPER_ID_SECRET_PASSPHRASE: 'dummy_secret_passphrase',
- CSC_LINK: 'dummy_csc_link',
- CSC_KEY_PASSWORD: 'dummy_csc_key_pass',
- APPLE_ID: 'dummy_apple_id',
- APPLE_ID_PASSWORD: 'dummy_apple_pass',
- AWS_ACCESS_KEY_ID: 'dummy_aws_access_key_id',
- AWS_SECRET_ACCESS_KEY: 'dummy_aws_secret_access_key',
- APPLE_CONTACT_EMAIL: 'dummy@email.com',
- APPLE_CONTACT_PHONE: '123456789',
- APPLE_DEMO_EMAIL: 'dummy.demo@email.com',
- APPLE_DEMO_PASSWORD: 'dummy_password',
- CLOUDFLARE_TOKEN: 'dummy_cloudflare_token',
- },
- 'dummy_github_token',
- {
- AS_REPO: 'App',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- desktop: 'ubuntu-latest',
- iOS: 'ubuntu-latest',
- android: 'ubuntu-latest',
- web: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps = {
- validateActor: mocks.PLATFORM_DEPLOY__VALIDATE_ACTOR__OUTSIDER__STEP_MOCKS,
- android: mocks.PLATFORM_DEPLOY__ANDROID__STEP_MOCKS,
- desktop: mocks.PLATFORM_DEPLOY__DESKTOP__STEP_MOCKS,
- iOS: mocks.PLATFORM_DEPLOY__IOS__STEP_MOCKS,
- web: mocks.PLATFORM_DEPLOY__WEB__STEP_MOCKS,
- postSlackMessageOnFailure: mocks.PLATFORM_DEPLOY__POST_SLACK_FAIL__STEP_MOCKS,
- postSlackMessageOnSuccess: mocks.PLATFORM_DEPLOY__POST_SLACK_SUCCESS__STEP_MOCKS,
- postGithubComment: mocks.PLATFORM_DEPLOY__POST_GITHUB_COMMENT__STEP_MOCKS,
- };
- const testMockJobs: MockJobs = {
- deployChecklist: {
- steps: mocks.PLATFORM_DEPLOY__DEPLOY_CHECKLIST__STEP_MOCKS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('platformDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertVerifyActorJobExecuted(result);
- assertions.assertDeployChecklistJobExecuted(result, true);
- assertions.assertAndroidJobExecuted(result, true, false, true);
- assertions.assertDesktopJobExecuted(result, true, false);
- assertions.assertIOSJobExecuted(result, true, false, true);
- assertions.assertWebJobExecuted(result, true);
- assertions.assertPostSlackOnFailureJobExecuted(result, false);
- assertions.assertPostSlackOnSuccessJobExecuted(result, true, false);
- assertions.assertPostGithubCommentJobExecuted(result, true, false);
- });
-
- it('as outsider - platform deploy does not execute', async () => {
- const repoPath = mockGithub.repo.getPath('testPlatformDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {
- ref: 'refs/tags/1.2.3',
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ref_type: 'tag',
- // eslint-disable-next-line @typescript-eslint/naming-convention
- ref_name: '1.2.3',
- },
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- MYAPP_UPLOAD_STORE_PASSWORD: 'dummy_store_password',
- MYAPP_UPLOAD_KEY_PASSWORD: 'dummy_key_password',
- BROWSERSTACK: 'dummy_browserstack',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- DEVELOPER_ID_SECRET_PASSPHRASE: 'dummy_secret_passphrase',
- CSC_LINK: 'dummy_csc_link',
- CSC_KEY_PASSWORD: 'dummy_csc_key_pass',
- APPLE_ID: 'dummy_apple_id',
- APPLE_ID_PASSWORD: 'dummy_apple_pass',
- AWS_ACCESS_KEY_ID: 'dummy_aws_access_key_id',
- AWS_SECRET_ACCESS_KEY: 'dummy_aws_secret_access_key',
- APPLE_CONTACT_EMAIL: 'dummy@email.com',
- APPLE_CONTACT_PHONE: '123456789',
- APPLE_DEMO_EMAIL: 'dummy.demo@email.com',
- APPLE_DEMO_PASSWORD: 'dummy_password',
- CLOUDFLARE_TOKEN: 'dummy_cloudflare_token',
- },
- 'dummy_github_token',
- {
- AS_REPO: 'App',
- },
- );
- act = utils.setJobRunners(
- act,
- {
- desktop: 'ubuntu-latest',
- iOS: 'ubuntu-latest',
- android: 'ubuntu-latest',
- web: 'ubuntu-latest',
- },
- workflowPath,
- );
- const testMockSteps = {
- validateActor: mocks.PLATFORM_DEPLOY__VALIDATE_ACTOR__OUTSIDER__STEP_MOCKS,
- android: mocks.PLATFORM_DEPLOY__ANDROID__STEP_MOCKS,
- desktop: mocks.PLATFORM_DEPLOY__DESKTOP__STEP_MOCKS,
- iOS: mocks.PLATFORM_DEPLOY__IOS__STEP_MOCKS,
- web: mocks.PLATFORM_DEPLOY__WEB__STEP_MOCKS,
- postSlackMessageOnFailure: mocks.PLATFORM_DEPLOY__POST_SLACK_FAIL__STEP_MOCKS,
- postSlackMessageOnSuccess: mocks.PLATFORM_DEPLOY__POST_SLACK_SUCCESS__STEP_MOCKS,
- postGithubComment: mocks.PLATFORM_DEPLOY__POST_GITHUB_COMMENT__STEP_MOCKS,
- };
- const testMockJobs: MockJobs = {
- deployChecklist: {
- steps: mocks.PLATFORM_DEPLOY__DEPLOY_CHECKLIST__STEP_MOCKS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'platformDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Author',
- logFile: utils.getLogFilePath('platformDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- assertions.assertVerifyActorJobExecuted(result);
- assertions.assertDeployChecklistJobExecuted(result, true);
- assertions.assertAndroidJobExecuted(result, false);
- assertions.assertDesktopJobExecuted(result, false);
- assertions.assertIOSJobExecuted(result, false);
- assertions.assertWebJobExecuted(result, false);
- assertions.assertPostSlackOnFailureJobExecuted(result, false);
- assertions.assertPostSlackOnSuccessJobExecuted(result, false);
- assertions.assertPostGithubCommentJobExecuted(result, true, false, false);
- });
- });
- });
-});
diff --git a/workflow_tests/preDeploy.test.ts b/workflow_tests/preDeploy.test.ts
deleted file mode 100644
index 1d467b0bd705..000000000000
--- a/workflow_tests/preDeploy.test.ts
+++ /dev/null
@@ -1,800 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/preDeployAssertions';
-import mocks from './mocks/preDeployMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import type {MockJobs} from './utils/JobMocker';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'preDeploy.yml'),
- dest: '.github/workflows/preDeploy.yml',
- },
-];
-
-describe('test workflow preDeploy', () => {
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testPreDeployWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- pushedBranches: ['different_branch'],
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- it('push to main - workflow executes', async () => {
- // get path to the local test repo
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
-
- // get path to the workflow file under test
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
-
- // instantiate Act in the context of the test repo and given workflow file
- let act = new ExtendedAct(repoPath, workflowPath);
-
- // set run parameters
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
-
- // set up mocks
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
-
- // run an event and get the result
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
-
- // assert results (some steps can run in parallel to each other so the order is not assured
- // therefore we can check which steps have been executed, but not the set job order
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- assertions.assertChooseDeployActionsJobExecuted(result);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertUpdateStagingJobExecuted(result);
- });
-
- it('different event than push - workflow does not execute', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
-
- // pull_request
- act = utils.setUpActParams(
- act,
- 'pull_request',
- {head: {ref: 'main'}},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- let result = await act.runEvent('pull_request', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result, false);
- assertions.assertLintJobExecuted(result, false);
- assertions.assertTestJobExecuted(result, false);
- assertions.assertChooseDeployActionsJobExecuted(result, false);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
-
- // workflow_dispatch
- act = utils.setUpActParams(
- act,
- 'workflow_dispatch',
- {},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- result = await act.runEvent('workflow_dispatch', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result, false);
- assertions.assertLintJobExecuted(result, false);
- assertions.assertTestJobExecuted(result, false);
- assertions.assertChooseDeployActionsJobExecuted(result, false);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- });
-
- describe('confirm passing build', () => {
- it('typecheck job failed - workflow exits', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: [utils.createMockStep('Run typecheck workflow', 'Running typecheck workflow - Typecheck workflow failed', 'TYPECHECK', null, null, null, null, false)],
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- expect(result).toEqual(
- expect.arrayContaining([utils.createStepAssertion('Run typecheck workflow', false, null, 'TYPECHECK', 'Running typecheck workflow - Typecheck workflow failed')]),
- );
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- expect(result).toEqual(
- expect.arrayContaining([
- utils.createStepAssertion('Announce failed workflow in Slack', true, null, 'CONFIRM_PASSING_BUILD', 'Announcing failed workflow in slack', [
- {key: 'SLACK_WEBHOOK', value: '***'},
- ]),
- utils.createStepAssertion('Exit failed workflow', false, 'Checks failed, exiting ~ typecheck: failure, lint: success, test: success'),
- ]),
- );
- assertions.assertChooseDeployActionsJobExecuted(result, false);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- });
-
- it('lint job failed - workflow exits', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: [utils.createMockStep('Run lint workflow', 'Running lint workflow - Lint workflow failed', 'LINT', null, null, null, null, false)],
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- expect(result).toEqual(expect.arrayContaining([utils.createStepAssertion('Run lint workflow', false, null, 'LINT', 'Running lint workflow - Lint workflow failed')]));
- assertions.assertTestJobExecuted(result);
- expect(result).toEqual(
- expect.arrayContaining([
- utils.createStepAssertion('Announce failed workflow in Slack', true, null, 'CONFIRM_PASSING_BUILD', 'Announcing failed workflow in slack', [
- {key: 'SLACK_WEBHOOK', value: '***'},
- ]),
- utils.createStepAssertion('Exit failed workflow', false, 'Checks failed, exiting ~ typecheck: success, lint: failure, test: success'),
- ]),
- );
- assertions.assertChooseDeployActionsJobExecuted(result, false);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- });
-
- it('test job failed - workflow exits', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: [utils.createMockStep('Run test workflow', 'Running test workflow - Test workflow failed', 'TEST', null, null, null, null, false)],
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- expect(result).toEqual(expect.arrayContaining([utils.createStepAssertion('Run test workflow', false, null, 'TEST', 'Running test workflow - Test workflow failed')]));
- expect(result).toEqual(
- expect.arrayContaining([
- utils.createStepAssertion('Announce failed workflow in Slack', true, null, 'CONFIRM_PASSING_BUILD', 'Announcing failed workflow in slack', [
- {key: 'SLACK_WEBHOOK', value: '***'},
- ]),
- utils.createStepAssertion('Exit failed workflow', false, 'Checks failed, exiting ~ typecheck: success, lint: success, test: failure'),
- ]),
- );
- assertions.assertChooseDeployActionsJobExecuted(result, false);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- });
-
- it('lint and test job succeed - workflow continues', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- assertions.assertChooseDeployActionsJobExecuted(result);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertUpdateStagingJobExecuted(result);
- });
- });
-
- describe('choose deploy actions', () => {
- describe('staging locked', () => {
- it('not automated PR - deploy skipped and comment left', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, 'push', {ref: 'refs/heads/main'}, {OS_BOTIFY_TOKEN: 'dummy_token', SLACK_WEBHOOK: 'dummy_slack_webhook'}, 'dummy_github_token');
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_LOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- assertions.assertChooseDeployActionsJobExecuted(result);
- assertions.assertSkipDeployJobExecuted(result);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- assertions.assertUpdateStagingJobFailed(result, false);
- });
-
- it('automated PR - deploy skipped, but no comment left', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, 'push', {ref: 'refs/heads/main'}, {OS_BOTIFY_TOKEN: 'dummy_token', SLACK_WEBHOOK: 'dummy_slack_webhook'}, 'dummy_github_token');
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_LOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- assertions.assertChooseDeployActionsJobExecuted(result);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- assertions.assertUpdateStagingJobFailed(result, false);
- });
- });
-
- describe('staging not locked', () => {
- it('not automated PR - proceed with deploy', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- assertions.assertChooseDeployActionsJobExecuted(result);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertUpdateStagingJobExecuted(result, true);
- assertions.assertUpdateStagingJobFailed(result, false);
- });
-
- it('automated PR - deploy skipped, but no comment left', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- },
- 'dummy_github_token',
- );
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'OSBotify',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- assertions.assertChooseDeployActionsJobExecuted(result);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result, false);
- assertions.assertUpdateStagingJobExecuted(result, false);
- assertions.assertUpdateStagingJobFailed(result, false);
- });
- });
-
- it('one of updateStaging steps failed - failure announced in Slack', async () => {
- const repoPath = mockGithub.repo.getPath('testPreDeployWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'preDeploy.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- 'push',
- {ref: 'refs/heads/main'},
- {
- OS_BOTIFY_TOKEN: 'dummy_token',
- SLACK_WEBHOOK: 'dummy_slack_webhook',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- },
- 'dummy_github_token',
- );
- const testMockSteps: MockStep = {
- confirmPassingBuild: mocks.CONFIRM_PASSING_BUILD_JOB_MOCK_STEPS,
- chooseDeployActions: mocks.CHOOSE_DEPLOY_ACTIONS_JOB_MOCK_STEPS__STAGING_UNLOCKED,
- skipDeploy: mocks.SKIP_DEPLOY_JOB_MOCK_STEPS,
- updateStaging: mocks.UPDATE_STAGING_JOB_MOCK_STEPS,
- };
- testMockSteps.updateStaging[3].mockWith = 'exit 1';
- const testMockJobs: MockJobs = {
- typecheck: {
- steps: mocks.TYPECHECK_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- lint: {
- steps: mocks.LINT_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- test: {
- steps: mocks.TEST_JOB_MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- createNewVersion: {
- steps: mocks.CREATE_NEW_VERSION_JOB_MOCK_STEPS,
- outputs: {
- // eslint-disable-next-line no-template-curly-in-string
- NEW_VERSION: '${{ steps.createNewVersion.outputs.NEW_VERSION }}',
- },
- runsOn: 'ubuntu-latest',
- },
- e2ePerformanceTests: {
- steps: mocks.PREDEPLOY__E2EPERFORMANCETESTS__MOCK_STEPS,
- runsOn: 'ubuntu-latest',
- },
- };
- const result = await act.runEvent('push', {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'preDeploy.yml'),
- mockSteps: testMockSteps,
- actor: 'Dummy Tester',
- logFile: utils.getLogFilePath('preDeploy', expect.getState().currentTestName),
- mockJobs: testMockJobs,
- });
- assertions.assertTypecheckJobExecuted(result);
- assertions.assertLintJobExecuted(result);
- assertions.assertTestJobExecuted(result);
- assertions.assertChooseDeployActionsJobExecuted(result);
- assertions.assertSkipDeployJobExecuted(result, false);
- assertions.assertCreateNewVersionJobExecuted(result);
- assertions.assertUpdateStagingJobFailed(result, true);
- });
- });
-});
diff --git a/workflow_tests/reviewerChecklist.test.ts b/workflow_tests/reviewerChecklist.test.ts
deleted file mode 100644
index 1fea2b60008c..000000000000
--- a/workflow_tests/reviewerChecklist.test.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/reviewerChecklistAssertions';
-import mocks from './mocks/reviewerChecklistMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'reviewerChecklist.yml'),
- dest: '.github/workflows/reviewerChecklist.yml',
- },
-];
-
-describe('test workflow reviewerChecklist', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testReviewerChecklistWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('event is pull_request_review', () => {
- const event = 'pull_request_review';
- const eventOptions = {};
- it('runs the workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('reviewerChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- const osbotifyActor = 'OSBotify';
- it('does not run the workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testReviewerChecklistWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- checklist: mocks.REVIEWERCHECKLIST__CHECKLIST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'reviewerChecklist.yml'),
- mockSteps: testMockSteps,
- actor: osbotifyActor,
- logFile: utils.getLogFilePath('reviewerChecklist', expect.getState().currentTestName),
- });
-
- assertions.assertChecklistJobExecuted(result, false);
- });
- });
- });
-});
diff --git a/workflow_tests/scripts/runWorkflowTests.sh b/workflow_tests/scripts/runWorkflowTests.sh
deleted file mode 100755
index c8ee88e33e99..000000000000
--- a/workflow_tests/scripts/runWorkflowTests.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/bin/bash
-
-source ./scripts/shellUtils.sh
-
-title 'GitHub Actions workflow tests'
-printf '\n'
-
-# Check setup
-info 'Checking environment setup'
-
-# Check if docker is installed
-if ! docker --version > /dev/null 2>&1; then
- error 'Docker is not installed'
- info 'Act requires docker to be installed. Please install docker and try again'
- exit 1
-fi
-info 'Docker installed'
-
-# Check if docker is running
-if ! docker info > /dev/null 2>&1; then
- error 'Docker is not running'
- info 'Act requires docker engine to be running. Enable docker engine and try again'
- exit 1
-fi
-info 'Docker engine running'
-
-# Check if act is installed
-if ! act --version > /dev/null 2>&1; then
- error 'Act not installed'
- info 'Install Act with brew install act and follow the documentation on first Act run (https://github.com/nektos/act#first-act-run)'
- exit 1
-fi
-info 'Act installed'
-
-# Check if ACT_BINARY is set
-if [[ -z ${ACT_BINARY} ]]; then
- info 'ACT_BINARY not set, checking .env file'
- if [ -f .env ]; then
- set -a
- source .env
- set +a
- else
- info '.env file does not exist'
- fi
- if [[ -z ${ACT_BINARY} ]]; then
- error 'ACT_BINARY variable not set'
- info 'To make sure Act behaves in a predictable manner please set the ACT_BINARY environment variable to the path to your Act binary'
- exit 1
- fi
-fi
-info 'ACT_BINARY environment variable set'
-
-if ! eval '${ACT_BINARY} --version' > /dev/null 2>&1; then
- error 'ACT_BINARY variable not set properly'
- info 'ACT_BINARY environment variable should be set to the path to your Act executable. Please set the variable correctly (try running "which act" to check the path)'
- exit 1
-fi
-info 'ACT_BINARY environment variable set to an Act executable'
-
-success 'Environment setup properly - running tests'
-
-# Run tests
-npm test -- --config=workflow_tests/jest.config.ts --runInBand "$@"
diff --git a/workflow_tests/test.test.ts b/workflow_tests/test.test.ts
deleted file mode 100644
index 926abff56bed..000000000000
--- a/workflow_tests/test.test.ts
+++ /dev/null
@@ -1,176 +0,0 @@
-import type {MockStep} from '@kie/act-js';
-import {MockGithub} from '@kie/mock-github';
-import type {CreateRepositoryFile} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/testAssertions';
-import mocks from './mocks/testMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO: CreateRepositoryFile[] = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'test.yml'),
- dest: '.github/workflows/test.yml',
- },
-];
-
-describe('test workflow test', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
- const osbotifyActor = 'OSBotify';
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testTestWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
-
- describe('pull request opened', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'opened',
- };
- it('runs all tests', async () => {
- const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- jest: mocks.TEST__JEST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'test.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('test', expect.getState().currentTestName),
- });
-
- assertions.assertJestJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- it('does not run tests', async () => {
- const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- jest: mocks.TEST__JEST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'test.yml'),
- mockSteps: testMockSteps,
- actor: osbotifyActor,
- logFile: utils.getLogFilePath('test', expect.getState().currentTestName),
- });
-
- assertions.assertJestJobExecuted(result, false);
- });
- });
- });
-
- describe('pull request synchronized', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'synchronize',
- };
- it('runs all tests', async () => {
- const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- jest: mocks.TEST__JEST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'test.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('test', expect.getState().currentTestName),
- });
-
- assertions.assertJestJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- it('does not run tests', async () => {
- const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- jest: mocks.TEST__JEST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'test.yml'),
- mockSteps: testMockSteps,
- actor: osbotifyActor,
- logFile: utils.getLogFilePath('test', expect.getState().currentTestName),
- });
-
- assertions.assertJestJobExecuted(result, false);
- });
- });
- });
-
- describe('event is workflow_call', () => {
- const event = 'workflow_call';
- const eventOptions = {};
- it('runs all tests', async () => {
- const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- jest: mocks.TEST__JEST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'test.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('test', expect.getState().currentTestName),
- });
-
- assertions.assertJestJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- it('runs all tests normally', async () => {
- const repoPath = mockGithub.repo.getPath('testTestWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'test.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps: MockStep = {
- jest: mocks.TEST__JEST__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'test.yml'),
- mockSteps: testMockSteps,
- actor: osbotifyActor,
- logFile: utils.getLogFilePath('test', expect.getState().currentTestName),
- });
-
- assertions.assertJestJobExecuted(result);
- });
- });
- });
-});
diff --git a/workflow_tests/testBuild.test.ts b/workflow_tests/testBuild.test.ts
deleted file mode 100644
index cd793fa9aaca..000000000000
--- a/workflow_tests/testBuild.test.ts
+++ /dev/null
@@ -1,754 +0,0 @@
-/* eslint-disable @typescript-eslint/naming-convention */
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/testBuildAssertions';
-import mocks from './mocks/testBuildMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'testBuild.yml'),
- dest: '.github/workflows/testBuild.yml',
- },
-];
-
-describe('test workflow testBuild', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
- const secrets = {
- OS_BOTIFY_TOKEN: 'dummy_osbotify_token',
- LARGE_SECRET_PASSPHRASE: '3xtr3m3ly_53cr3t_p455w0rd',
- AWS_ACCESS_KEY_ID: 'dummy_aws_access_kry_id',
- AWS_SECRET_ACCESS_KEY: 'dummy_aws_secret_access_key',
- DEVELOPER_ID_SECRET_PASSPHRASE: 'dummy_developer_id_secret_passphrase',
- CSC_LINK: 'dummy_csc_link',
- CSC_KEY_PASSWORD: 'dummy_csc_key_password',
- APPLE_ID_PASSWORD: 'dummy_apple_id_password',
- APPLE_ID: 'dummy_apple_id_value',
- MYAPP_UPLOAD_STORE_PASSWORD: 'dummy_myapp_upload_store_password',
- MYAPP_UPLOAD_KEY_PASSWORD: 'dummy_myapp_upload_key_password',
- };
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testTestBuildWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('event is workflow_dispatch', () => {
- const event = 'workflow_dispatch';
- const inputs = {
- PULL_REQUEST_NUMBER: '1234',
- };
- it('executes workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result);
- assertions.assertAndroidJobExecuted(result, 'test-ref');
- assertions.assertIOSJobExecuted(result, 'test-ref');
- assertions.assertDesktopJobExecuted(result, 'test-ref');
- assertions.assertWebJobExecuted(result, 'test-ref');
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref');
- });
- describe('actor is not a team member', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('actor is not a team member and PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('android fails', () => {
- it('executes workflow, failure reflected', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: utils.deepCopy(mocks.TESTBUILD__ANDROID__STEP_MOCKS),
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- testMockSteps.android[5] = utils.createMockStep('Decrypt keystore', 'Decrypt keystore', 'ANDROID', [], ['LARGE_SECRET_PASSPHRASE'], {}, {}, false);
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result);
- assertions.assertAndroidJobExecuted(result, 'test-ref', true, 5);
- assertions.assertIOSJobExecuted(result, 'test-ref');
- assertions.assertDesktopJobExecuted(result, 'test-ref');
- assertions.assertWebJobExecuted(result, 'test-ref');
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', true, 'failure', 'success', 'success', 'success');
- });
- });
- describe('iOS fails', () => {
- it('executes workflow, failure reflected', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: utils.deepCopy(mocks.TESTBUILD__IOS__STEP_MOCKS),
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- testMockSteps.iOS[8] = utils.createMockStep('Install cocoapods', 'Install cocoapods', 'IOS', ['timeout_minutes', 'max_attempts', 'command'], [], {}, {}, false);
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result);
- assertions.assertAndroidJobExecuted(result, 'test-ref');
- assertions.assertIOSJobExecuted(result, 'test-ref', true, 8);
- assertions.assertDesktopJobExecuted(result, 'test-ref');
- assertions.assertWebJobExecuted(result, 'test-ref');
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', true, 'success', 'failure', 'success', 'success');
- });
- });
- describe('desktop fails', () => {
- it('executes workflow, failure reflected', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: utils.deepCopy(mocks.TESTBUILD__DESKTOP__STEP_MOCKS),
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- testMockSteps.desktop[3] = utils.createMockStep(
- 'Decrypt Developer ID Certificate',
- 'Decrypt Developer ID Certificate',
- 'DESKTOP',
- [],
- ['DEVELOPER_ID_SECRET_PASSPHRASE'],
- {},
- {},
- false,
- );
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result);
- assertions.assertAndroidJobExecuted(result, 'test-ref');
- assertions.assertIOSJobExecuted(result, 'test-ref');
- assertions.assertDesktopJobExecuted(result, 'test-ref', true, 3);
- assertions.assertWebJobExecuted(result, 'test-ref');
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', true, 'success', 'success', 'failure', 'success');
- });
- });
- describe('web fails', () => {
- it('executes workflow, failure reflected', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, {}, secrets, githubToken, {}, inputs);
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: utils.deepCopy(mocks.TESTBUILD__WEB__STEP_MOCKS),
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- testMockSteps.web[3] = utils.createMockStep(
- 'Configure AWS Credentials',
- 'Configure AWS Credentials',
- 'WEB',
- ['aws-access-key-id', 'aws-secret-access-key', 'aws-region'],
- [],
- {},
- {},
- false,
- );
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result);
- assertions.assertAndroidJobExecuted(result, 'test-ref');
- assertions.assertIOSJobExecuted(result, 'test-ref');
- assertions.assertDesktopJobExecuted(result, 'test-ref');
- assertions.assertWebJobExecuted(result, 'test-ref', true, 3);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', true, 'success', 'success', 'success', 'failure');
- });
- });
- });
- describe('pull request opened', () => {
- const event = 'pull_request_target';
- const eventOptions = {
- action: 'opened',
- number: '1234',
- pull_request: {
- head: {
- sha: 'test-ref',
- },
- },
- };
- it('executes workflow, without getBranchRef', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref');
- assertions.assertIOSJobExecuted(result, 'test-ref');
- assertions.assertDesktopJobExecuted(result, 'test-ref');
- assertions.assertWebJobExecuted(result, 'test-ref');
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref');
- });
- describe('actor is not a team member', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('actor is not a team member and PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- });
- describe('pull request synchronized', () => {
- const event = 'pull_request_target';
- const eventOptions = {
- action: 'synchronize',
- number: '1234',
- pull_request: {
- head: {
- sha: 'test-ref',
- },
- },
- };
- it('executes workflow, without getBranchRef', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref');
- assertions.assertIOSJobExecuted(result, 'test-ref');
- assertions.assertDesktopJobExecuted(result, 'test-ref');
- assertions.assertWebJobExecuted(result, 'test-ref');
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref');
- });
- describe('actor is not a team member', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('actor is not a team member and PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- });
- describe('pull request labeled', () => {
- const event = 'pull_request_target';
- const eventOptions = {
- action: 'labeled',
- number: '1234',
- pull_request: {
- head: {
- sha: 'test-ref',
- },
- },
- };
- it('executes workflow, withuout getBranchRef', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref');
- assertions.assertIOSJobExecuted(result, 'test-ref');
- assertions.assertDesktopJobExecuted(result, 'test-ref');
- assertions.assertWebJobExecuted(result, 'test-ref');
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref');
- });
- describe('actor is not a team member', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_HAS_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- describe('actor is not a team member and PR does not have READY_TO_BUILD label', () => {
- it('stops the workflow after validation', async () => {
- const repoPath = mockGithub.repo.getPath('testTestBuildWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'testBuild.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, secrets, githubToken, {});
- act = utils.setJobRunners(act, {iOS: 'ubuntu-latest', desktop: 'ubuntu-latest', web: 'ubuntu-latest', android: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- validateActor: mocks.TESTBUILD__VALIDATEACTOR__NO_TEAM_MEMBER_NO_FLAG__STEP_MOCKS,
- getBranchRef: mocks.TESTBUILD__GETBRANCHREF__STEP_MOCKS,
- android: mocks.TESTBUILD__ANDROID__STEP_MOCKS,
- iOS: mocks.TESTBUILD__IOS__STEP_MOCKS,
- desktop: mocks.TESTBUILD__DESKTOP__STEP_MOCKS,
- web: mocks.TESTBUILD__WEB__STEP_MOCKS,
- postGithubComment: mocks.TESTBUILD__POSTGITHUBCOMMENT__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'testBuild.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('testBuild', expect.getState().currentTestName),
- });
-
- assertions.assertValidateActorJobExecuted(result, '1234');
- assertions.assertGetBranchRefJobExecuted(result, false);
- assertions.assertAndroidJobExecuted(result, 'test-ref', false);
- assertions.assertIOSJobExecuted(result, 'test-ref', false);
- assertions.assertDesktopJobExecuted(result, 'test-ref', false);
- assertions.assertWebJobExecuted(result, 'test-ref', false);
- assertions.assertPostGithubCommentJobExecuted(result, 'test-ref', '1234', false);
- });
- });
- });
-});
diff --git a/workflow_tests/utils/ExtendedAct.ts b/workflow_tests/utils/ExtendedAct.ts
deleted file mode 100644
index f5a0742afd76..000000000000
--- a/workflow_tests/utils/ExtendedAct.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/* eslint-disable @typescript-eslint/dot-notation */
-// This eslint-disable comment is here to allow accessing private properties in the Act class
-import type {RunOpts, Step, Workflow} from '@kie/act-js';
-import {Act} from '@kie/act-js';
-import os from 'os';
-import path from 'path';
-import JobMocker from './JobMocker';
-import type {MockJobs} from './JobMocker';
-
-type ExtendedActOpts = RunOpts & {actor?: string; workflowFile?: string; mockJobs?: MockJobs};
-
-type ActOptions = {
- cwd: string;
- actArguments: string[];
- proxy: unknown;
-};
-
-// @ts-expect-error Override shouldn't be done on private methods wait until https://github.com/kiegroup/act-js/issues/77 is resolved or try to create a params workaround
-class ExtendedAct extends Act {
- async parseRunOpts(opts?: ExtendedActOpts): Promise {
- const {cwd, actArguments, proxy} = await (super['parseRunOpts'] as (opts?: ExtendedActOpts) => Promise)(opts);
-
- if (opts?.actor) {
- actArguments.push('--actor', opts.actor);
- }
-
- if (os.arch() === 'arm64') {
- actArguments.push('--container-architecture', 'linux/amd64');
- }
-
- return {cwd, actArguments, proxy};
- }
-
- async runEvent(event: string, opts?: ExtendedActOpts): Promise {
- const {mockJobs, ...vanillaOpts} = opts ?? {};
-
- if (mockJobs) {
- await this.handleJobMocking((workflow) => workflow.events.includes(event), {mockJobs, workflowFile: vanillaOpts.workflowFile, cwd: vanillaOpts.cwd});
- }
-
- return super.runEvent(event, vanillaOpts);
- }
-
- async handleJobMocking(filter: (workflow: Workflow) => boolean, opts: ExtendedActOpts): Promise {
- let workflowFiles: string[];
-
- if (opts.workflowFile) {
- workflowFiles = [path.basename(opts.workflowFile)];
- } else if (this['workflowFile'] !== this['cwd']) {
- workflowFiles = [path.basename(this['workflowFile'] as string)];
- } else {
- const availableWorkflows = await this.list(undefined, opts.cwd, opts.workflowFile);
- workflowFiles = availableWorkflows.filter(filter).map((workflow: Workflow) => workflow.workflowFile);
- }
-
- return workflowFiles.map((workflowFile) => {
- const jobMocker = new JobMocker(workflowFile, opts.cwd ?? (this['cwd'] as string));
- return jobMocker.mock(opts.mockJobs);
- });
- }
-}
-
-export default ExtendedAct;
diff --git a/workflow_tests/utils/JobMocker.ts b/workflow_tests/utils/JobMocker.ts
deleted file mode 100644
index 9434b52ef0a5..000000000000
--- a/workflow_tests/utils/JobMocker.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import type {StepIdentifier} from '@kie/act-js';
-import type {PathOrFileDescriptor} from 'fs';
-import fs from 'fs';
-import path from 'path';
-import yaml from 'yaml';
-
-// eslint-disable-next-line @typescript-eslint/naming-convention
-type YamlMockJob = Omit & {'runs-on'?: string};
-
-type YamlWorkflow = {
- jobs: Record;
-};
-
-type MockJob = {
- steps: StepIdentifier[];
- uses?: string;
- secrets?: string[];
- with?: string;
- outputs?: Record;
- runsOn: string;
-};
-
-type MockJobs = Record;
-
-class JobMocker {
- workflowFile: string;
-
- cwd: string;
-
- constructor(workflowFile: string, cwd: string) {
- this.workflowFile = workflowFile;
- this.cwd = cwd;
- }
-
- mock(mockJobs: MockJobs = {}) {
- const filePath = this.getWorkflowPath();
- const workflow = this.readWorkflowFile(filePath);
-
- Object.entries(mockJobs).forEach(([jobId, mockJob]) => {
- const job = this.locateJob(workflow, jobId);
- if (job) {
- if (job.uses) {
- delete job.uses;
- }
- if (job.secrets) {
- delete job.secrets;
- }
- let jobWith: string | undefined;
- if (job.with) {
- jobWith = job.with;
- delete job.with;
- }
- job.steps = mockJob.steps.map((step) => {
- const mockStep = {
- name: step.name,
- run: step.mockWith,
- } as StepIdentifier;
- if (step.id) {
- mockStep.id = step.id;
- }
- if (jobWith) {
- mockStep.with = jobWith;
- }
- return mockStep;
- });
- if (mockJob.outputs) {
- job.outputs = mockJob.outputs;
- }
- if (mockJob.runsOn) {
- job['runs-on'] = mockJob.runsOn;
- }
- } else {
- throw new Error('Could not find job');
- }
- });
- return this.writeWorkflowFile(filePath, workflow);
- }
-
- locateJob(workflow: YamlWorkflow, jobId: string): YamlMockJob {
- return workflow.jobs[jobId];
- }
-
- getWorkflowPath(): string {
- if (fs.existsSync(path.join(this.cwd, this.workflowFile))) {
- return path.join(this.cwd, this.workflowFile);
- }
- if (this.cwd.endsWith('.github')) {
- return path.join(this.cwd, 'workflows', this.workflowFile);
- }
- if (fs.existsSync(path.join(this.cwd, '.github', 'workflows', this.workflowFile))) {
- return path.join(this.cwd, '.github', 'workflows', this.workflowFile);
- }
- throw new Error(`Could not locate ${this.workflowFile}`);
- }
-
- readWorkflowFile(location: PathOrFileDescriptor): YamlWorkflow {
- return yaml.parse(fs.readFileSync(location, 'utf8')) as YamlWorkflow;
- }
-
- writeWorkflowFile(location: PathOrFileDescriptor, data: YamlWorkflow) {
- return fs.writeFileSync(location, yaml.stringify(data), 'utf8');
- }
-}
-
-export default JobMocker;
-export type {MockJob, MockJobs, YamlWorkflow, YamlMockJob};
diff --git a/workflow_tests/utils/preGenerateTest.ts b/workflow_tests/utils/preGenerateTest.ts
deleted file mode 100644
index 2c2e18eaeafa..000000000000
--- a/workflow_tests/utils/preGenerateTest.ts
+++ /dev/null
@@ -1,297 +0,0 @@
-/* eslint no-console: ["error", { allow: ["warn", "log"] }] */
-import type {StepIdentifier} from '@kie/act-js';
-import type {PathLike} from 'fs';
-import fs from 'fs';
-import path from 'path';
-import {exit} from 'process';
-import yaml from 'yaml';
-import type {YamlMockJob, YamlWorkflow} from './JobMocker';
-
-const workflowsDirectory = path.resolve(__dirname, '..', '..', '.github', 'workflows');
-const workflowTestsDirectory = path.resolve(__dirname, '..');
-const workflowTestMocksDirectory = path.join(workflowTestsDirectory, 'mocks');
-const workflowTestAssertionsDirectory = path.join(workflowTestsDirectory, 'assertions');
-const workflowFilePattern = '\\w+\\.yml';
-const workflowFileRegex = new RegExp(workflowFilePattern, 'g');
-
-const capitalize = (s: string): string => (s && s.charAt(0).toUpperCase() + s.slice(1)) || '';
-const mockFileTemplate = (mockSteps: string, exports: string) => `const utils = require('../utils/utils');
-${mockSteps}
-${exports}
-`;
-
-const assertionFileTemplate = (jobAssertions: string, exports: string) => `import type {Step} from '@kie/act-js';
-import * as utils from 'workflow_tests/utils/utils';
-
-${jobAssertions}
-${exports}
-`;
-
-const testFileTemplate = (workflowName: string) => `const path = require('path');
-const kieMockGithub = require('@kie/mock-github');
-const utils = require('./utils/utils');
-const assertions = require('./assertions/${workflowName}Assertions');
-const mocks = require('./mocks/${workflowName}Mocks');
-const ExtendedAct = require('./utils/ExtendedAct').default;
-
-jest.setTimeout(90 * 1000);
-let mockGithub;
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', '${workflowName}.yml'),
- dest: '.github/workflows/${workflowName}.yml',
- },
-];
-
-describe('test workflow ${workflowName}', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new kieMockGithub.MockGithub({
- repo: {
- test${capitalize(workflowName)}WorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
-
- // if any branches besides main are need add: pushedBranches: ['staging', 'production'],
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- it('test stub', async () => {
- const repoPath = mockGithub.repo.getPath('test${capitalize(workflowName)}WorkflowRepo') || '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', '${workflowName}.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(
- act,
- '[EVENT]',
- {},
- {},
- githubToken,
- );
- const testMockSteps = {
- // mock steps with imported mocks
- };
- const result = await act
- .runEvent('[EVENT]', {
- workflowFile: path.join(repoPath, '.github', 'workflows', '${workflowName}.yml'),
- mockSteps: testMockSteps,
- actor,
- });
-
- // assert execution with imported assertions
- });
-});
-`;
-
-const mockStepTemplate = (stepMockName: string, step: StepIdentifier, jobId: string | undefined) => `
-const ${stepMockName} = utils.createMockStep(
- '${step.name ?? ''}',
- '${step.name ?? ''}',
- ${jobId ? `'${jobId.toUpperCase()}'` : 'null'},
- ${step.inputs ? JSON.stringify(step.inputs).replaceAll('"', "'") : 'null'},
- ${step.envs ? JSON.stringify(step.envs).replaceAll('"', "'") : 'null'},
- // add outputs if needed
-);`;
-
-const stepAssertionTemplate = (stepName: string, jobId: string, stepMessage: string, inputs: string[] = [], envs: string[] = []): string => {
- const inputsString = inputs.map((input) => `{key: '${input}', value: '[FILL_IN]'}`).join(',');
- const envsString = envs.map((env) => `{key: '${env}', value: '[FILL_IN]'}`).join(',');
-
- return `
- utils.createStepAssertion(
- '${stepName}',
- true,
- null,
- '${jobId}',
- '${stepMessage}',
- [${inputsString}],
- [${envsString}],
- ),`;
-};
-
-const jobMocksTemplate = (jobMocksName: string, stepMocks: string[]): string => {
- const stepMocksString = stepMocks.map((stepMock) => `${stepMock}`).join(',');
-
- return `const ${jobMocksName} = [${stepMocksString}\n];`;
-};
-
-const jobAssertionTemplate = (jobAssertionName: string, stepAssertionsContent: string) => `
-function ${jobAssertionName}(workflowResult: Step[], didExecute = true) {
- const steps = [\n${stepAssertionsContent}\n];
-
- for (const expectedStep of steps) {
- if (didExecute) {
- expect(workflowResult).toEqual(expect.arrayContaining([expectedStep]));
- } else {
- expect(workflowResult).not.toEqual(expect.arrayContaining([expectedStep]));
- }
- }
-};`;
-
-const mocksExportsTemplate = (jobMocks: string[]): string => {
- const jobMocksString = jobMocks.map((jobMock) => ` ${jobMock}`).join(',\n');
-
- return `\nmodule.exports = {\n${jobMocksString}\n};\n`;
-};
-
-const assertionsExportsTemplate = (jobAssertions: string[]): string => {
- const assertionsString = jobAssertions.join(',\n');
- // There are other pre-generated files using imports from here, so to keep the interface uniform it's better to just disable it
- const eslintDisable = jobAssertions.length === 1 ? '// eslint-disable-next-line import/prefer-default-export\n' : '';
-
- return `\n${eslintDisable}export default {\n${assertionsString}\n};\n`;
-};
-
-const checkArguments = (args: string[]) => {
- if (args.length > 0 && args[0]) {
- return;
- }
- console.warn('Please provide workflow file name');
- exit(1);
-};
-const checkWorkflowFileName = (fileName: string) => {
- if (workflowFileRegex.test(fileName)) {
- return;
- }
- console.warn(`Please provide a valid workflow file name ([workflow].yml) instead of ${fileName}`);
- exit(1);
-};
-const checkWorkflowFilePath = (filePath: PathLike) => {
- if (fs.existsSync(filePath)) {
- return;
- }
- console.warn(`Provided workflow file does not exist: ${filePath.toString()}`);
- exit(1);
-};
-const checkIfTestFileExists = (testsDirectory: string, testFileName: string) => {
- if (!fs.existsSync(path.join(testsDirectory, testFileName))) {
- return;
- }
- console.warn(`The test file ${testFileName} already exists, exiting`);
- exit(1);
-};
-const checkIfMocksFileExists = (mocksDirectory: string, mocksFileName: string) => {
- if (!fs.existsSync(path.join(mocksDirectory, mocksFileName))) {
- return;
- }
- console.warn(`The mocks file ${mocksFileName} already exists, exiting`);
- exit(1);
-};
-const checkIfAssertionsFileExists = (assertionsDirectory: string, assertionsFileName: string) => {
- if (!fs.existsSync(path.join(assertionsDirectory, assertionsFileName))) {
- return;
- }
- console.warn(`The assertions file ${assertionsFileName} already exists, exiting`);
- exit(1);
-};
-const parseWorkflowFile = (workflow: YamlWorkflow) => {
- const workflowJobs: Record = {};
- Object.entries(workflow.jobs).forEach(([jobId, job]) => {
- workflowJobs[jobId] = {
- steps: [],
- };
- job.steps.forEach((step) => {
- const workflowStep = {
- name: step.name ?? '',
- inputs: Object.keys(step.with ?? {}),
- envs: step.envs ?? [],
- } as StepIdentifier;
- workflowJobs[jobId].steps.push(workflowStep);
- });
- });
- return workflowJobs;
-};
-const getMockFileContent = (workflowName: string, jobs: Record): string => {
- let content = '';
- const jobMocks: string[] = [];
- Object.entries(jobs).forEach(([jobId, job]) => {
- let mockStepsContent = `\n// ${jobId.toLowerCase()}`;
- const stepMocks: string[] = [];
- job.steps.forEach((step) => {
- const stepMockName = `${workflowName.toUpperCase()}__${jobId.toUpperCase()}__${step.name
- .replaceAll(' ', '_')
- .replaceAll('-', '_')
- .replaceAll(',', '')
- .replaceAll('#', '')
- .replaceAll('.ts', '')
- .replaceAll('.js', '')
- .toUpperCase()}__STEP_MOCK`;
- stepMocks.push(stepMockName);
- mockStepsContent += mockStepTemplate(stepMockName, step, jobId);
- });
-
- const jobMocksName = `${workflowName.toUpperCase()}__${jobId.toUpperCase()}__STEP_MOCKS`;
- jobMocks.push(jobMocksName);
- mockStepsContent += jobMocksTemplate(jobMocksName, stepMocks);
- content += mockStepsContent;
- });
- return mockFileTemplate(content, mocksExportsTemplate(jobMocks));
-};
-
-const getAssertionsFileContent = (jobs: Record): string => {
- let content = '';
- const jobAssertions: string[] = [];
-
- Object.entries(jobs).forEach(([jobId, job]) => {
- let stepAssertionsContent = '';
- job.steps.forEach((step: StepIdentifier) => {
- stepAssertionsContent += stepAssertionTemplate(step.name, jobId.toUpperCase(), step.name, step.inputs, step.envs);
- });
- const jobAssertionName = `assert${jobId.charAt(0).toUpperCase() + jobId.slice(1)}JobExecuted`;
- jobAssertions.push(jobAssertionName);
- content += jobAssertionTemplate(jobAssertionName, stepAssertionsContent);
- });
-
- return assertionFileTemplate(content, assertionsExportsTemplate(jobAssertions));
-};
-
-const getTestFileContent = (workflowName: string): string => testFileTemplate(workflowName);
-
-const callArgs = process.argv.slice(2);
-checkArguments(callArgs);
-
-const workflowFileName = callArgs[0];
-checkWorkflowFileName(workflowFileName);
-
-const workflowName = workflowFileName.slice(0, -4);
-const workflowFilePath = path.join(workflowsDirectory, workflowFileName);
-checkWorkflowFilePath(workflowFilePath);
-
-const workflowTestFileName = `${workflowName}.test.js`;
-checkIfTestFileExists(workflowTestsDirectory, workflowTestFileName);
-
-const workflowTestMocksFileName = `${workflowName}Mocks.js`;
-checkIfMocksFileExists(workflowTestMocksDirectory, workflowTestMocksFileName);
-
-const workflowTestAssertionsFileName = `${workflowName}Assertions.ts`;
-checkIfAssertionsFileExists(workflowTestAssertionsDirectory, workflowTestAssertionsFileName);
-
-const workflow = yaml.parse(fs.readFileSync(workflowFilePath, 'utf8')) as YamlWorkflow;
-const workflowJobs = parseWorkflowFile(workflow);
-
-const mockFileContent = getMockFileContent(workflowName, workflowJobs);
-const mockFilePath = path.join(workflowTestMocksDirectory, workflowTestMocksFileName);
-console.log(`Creating mock file ${mockFilePath}`);
-fs.writeFileSync(mockFilePath, mockFileContent);
-console.log(`Mock file ${mockFilePath} created`);
-
-const assertionsFileContent = getAssertionsFileContent(workflowJobs);
-const assertionsFilePath = path.join(workflowTestAssertionsDirectory, workflowTestAssertionsFileName);
-console.log(`Creating assertions file ${assertionsFilePath}`);
-fs.writeFileSync(assertionsFilePath, assertionsFileContent);
-console.log(`Assertions file ${assertionsFilePath} created`);
-
-const testFileContent = getTestFileContent(workflowName);
-const testFilePath = path.join(workflowTestsDirectory, workflowTestFileName);
-console.log(`Creating test file ${testFilePath}`);
-fs.writeFileSync(testFilePath, testFileContent);
-console.log(`Test file ${testFilePath} created`);
diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts
deleted file mode 100644
index 1fd60e3f92bc..000000000000
--- a/workflow_tests/utils/utils.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-import type {EventJSON, StepIdentifier} from '@kie/act-js';
-import fs from 'fs';
-import path from 'path';
-import yaml from 'yaml';
-import type ExtendedAct from './ExtendedAct';
-
-type StepAssertionInputEntry = {key: string; value: string | boolean};
-
-type StepAssertion = {
- name: string;
- status: number;
- output: string;
-};
-
-type Jobs = Record<
- string,
- {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- 'runs-on': string;
- }
->;
-
-type Workflow = {
- jobs: Jobs;
-};
-
-function setUpActParams(
- act: ExtendedAct,
- event: string | null = null,
- eventOptions: EventJSON | null = null,
- secrets: Record | null = null,
- githubToken: string | null = null,
- envVars: Record | null = null,
- inputs: Record | null = null,
-): ExtendedAct {
- let updatedAct = act;
-
- if (event && eventOptions) {
- // according to `Act` docs event data should be under the key with the event name (`[event]: eventOptions`), but
- // for some event types this does not work (like `issues`), but providing the data on the JSON top level does,
- // hence `...eventOptions` - this seems to cover all options
- const eventData = {
- [event]: eventOptions,
- ...eventOptions,
- };
- updatedAct = updatedAct.setEvent(eventData);
- }
-
- if (secrets) {
- Object.entries(secrets).forEach(([key, value]) => {
- updatedAct = updatedAct.setSecret(key, value);
- });
- }
-
- if (githubToken) {
- updatedAct = updatedAct.setGithubToken(githubToken);
- }
-
- if (envVars) {
- Object.entries(envVars).forEach(([key, value]) => {
- updatedAct = updatedAct.setEnv(key, value);
- });
- }
-
- if (inputs) {
- Object.entries(inputs).forEach(([key, value]) => {
- updatedAct = updatedAct.setInput(key, value);
- });
- }
-
- return updatedAct;
-}
-
-function createMockStep(
- name: string,
- message: string,
- jobId: string | null = null,
- inputs: string[] | null = null,
- inEnvs: string[] | null = null,
- outputs: Record | null = null,
- outEnvs: Record | null = null,
- isSuccessful = true,
- id: string | null = null,
-): StepIdentifier {
- const mockStepName = name;
- let mockWithCommand = 'echo [MOCK]';
- if (jobId) {
- mockWithCommand += ` [${jobId}]`;
- }
- mockWithCommand += ` ${message}`;
- if (inputs) {
- inputs.forEach((input) => {
- mockWithCommand += `, ${input}="\${{ inputs.${input} && inputs.${input} || github.event.inputs.${input} }}"`;
- });
- }
- if (inEnvs) {
- inEnvs.forEach((env) => {
- mockWithCommand += `, ${env}="\${{ env.${env} }}"`;
- });
- }
- if (outputs) {
- Object.entries(outputs).forEach(([key, value]) => {
- mockWithCommand += `\necho "${key}=${value}" >> "$GITHUB_OUTPUT"`;
- });
- }
- if (outEnvs) {
- Object.entries(outEnvs).forEach(([key, value]) => {
- mockWithCommand += `\necho "${key}=${value}" >> "$GITHUB_ENV"`;
- });
- }
- if (!isSuccessful) {
- mockWithCommand += '\nexit 1';
- }
- if (!id) {
- return {
- name: mockStepName,
- mockWith: mockWithCommand,
- };
- }
-
- return {
- id,
- name: mockStepName,
- mockWith: mockWithCommand,
- };
-}
-
-function createStepAssertion(
- name: string,
- isSuccessful = true,
- expectedOutput: string | null = null,
- jobId: string | null = null,
- message: string | null = null,
- inputs: StepAssertionInputEntry[] | null = null,
- envs: StepAssertionInputEntry[] | null = null,
-): StepAssertion {
- const stepName = `Main ${name}`;
- const stepStatus = isSuccessful ? 0 : 1;
- let stepOutput: string;
- if (expectedOutput !== null) {
- stepOutput = expectedOutput;
- } else {
- stepOutput = '[MOCK]';
- if (jobId) {
- stepOutput += ` [${jobId}]`;
- }
- if (message) {
- stepOutput += ` ${message}`;
- }
- if (inputs) {
- inputs.forEach((input) => {
- stepOutput += `, ${input.key}=${input.value}`;
- });
- }
- if (envs) {
- envs.forEach((env) => {
- stepOutput += `, ${env.key}=${env.value}`;
- });
- }
- }
- return {
- name: stepName,
- status: stepStatus,
- output: stepOutput,
- };
-}
-
-function setJobRunners(act: ExtendedAct, jobs: Record, workflowPath: string): ExtendedAct {
- if (!act || !jobs || !workflowPath) {
- return act;
- }
-
- const workflow = yaml.parse(fs.readFileSync(workflowPath, 'utf8')) as Workflow;
- Object.entries(jobs).forEach(([jobId, runner]) => {
- const job = workflow.jobs[jobId];
- job['runs-on'] = runner;
- });
- fs.writeFileSync(workflowPath, yaml.stringify(workflow), 'utf8');
- return act;
-}
-
-function deepCopy(originalObject: TObject): TObject {
- return JSON.parse(JSON.stringify(originalObject)) as TObject;
-}
-
-function getLogFilePath(workflowName: string, testName: string | undefined): string {
- if (!testName) {
- throw new Error();
- }
-
- const logsDir = path.resolve(__dirname, '..', 'logs');
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir);
- }
- const workflowTestsLogDir = path.resolve(logsDir, workflowName);
- if (!fs.existsSync(workflowTestsLogDir)) {
- fs.mkdirSync(workflowTestsLogDir);
- }
- const cleanTestName = testName.replace(' ', '_').replace('-', '_').substr(0, 240);
- return path.resolve(workflowTestsLogDir, `${cleanTestName}.log`);
-}
-
-function removeMockRepoDir() {
- const mockDirRepo = path.resolve(__dirname, '..', '..', 'repo');
- if (fs.existsSync(mockDirRepo)) {
- fs.rmSync(mockDirRepo, {recursive: true, force: true});
- }
-}
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- {
- src: path.resolve(__dirname, '..', '..', '.github', 'actions'),
- dest: '.github/actions',
- },
- {
- src: path.resolve(__dirname, '..', '..', '.github', 'libs'),
- dest: '.github/libs',
- },
- {
- src: path.resolve(__dirname, '..', '..', '.github', 'scripts'),
- dest: '.github/scripts',
- },
-];
-
-export {setUpActParams, createMockStep, createStepAssertion, setJobRunners, deepCopy, getLogFilePath, FILES_TO_COPY_INTO_TEST_REPO, removeMockRepoDir};
diff --git a/workflow_tests/validateGithubActions.test.ts b/workflow_tests/validateGithubActions.test.ts
deleted file mode 100644
index f4972a9ae653..000000000000
--- a/workflow_tests/validateGithubActions.test.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/validateGithubActionsAssertions';
-import mocks from './mocks/validateGithubActionsMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'validateGithubActions.yml'),
- dest: '.github/workflows/validateGithubActions.yml',
- },
-];
-
-describe('test workflow validateGithubActions', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testValidateGithubActionsWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('pull request opened', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'opened',
- };
- it('executes verification', async () => {
- const repoPath = mockGithub.repo.getPath('testValidateGithubActionsWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'validateGithubActions.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- verify: mocks.VALIDATEGITHUBACTIONS__VERIFY__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'validateGithubActions.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('validateGithubActions', expect.getState().currentTestName),
- });
-
- assertions.assertVerifyJobExecuted(result);
- });
- });
- describe('pull request synchronized', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'synchronize',
- };
- it('executes verification', async () => {
- const repoPath = mockGithub.repo.getPath('testValidateGithubActionsWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'validateGithubActions.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- verify: mocks.VALIDATEGITHUBACTIONS__VERIFY__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'validateGithubActions.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('validateGithubActions', expect.getState().currentTestName),
- });
-
- assertions.assertVerifyJobExecuted(result);
- });
- });
-});
diff --git a/workflow_tests/verifyPodfile.test.ts b/workflow_tests/verifyPodfile.test.ts
deleted file mode 100644
index 6124cdc856c1..000000000000
--- a/workflow_tests/verifyPodfile.test.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/verifyPodfileAssertions';
-import mocks from './mocks/verifyPodfileMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'verifyPodfile.yml'),
- dest: '.github/workflows/verifyPodfile.yml',
- },
-];
-
-describe('test workflow verifyPodfile', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
- const osbotifyActor = 'OSBotify';
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testVerifyPodfileWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('pull request opened', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'opened',
- };
- it('executes workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- verify: mocks.VERIFYPODFILE__VERIFY__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('verifyPodfile', expect.getState().currentTestName),
- });
-
- assertions.assertVerifyJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- it('does not execute workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- verify: mocks.VERIFYPODFILE__VERIFY__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'),
- mockSteps: testMockSteps,
- actor: osbotifyActor,
- logFile: utils.getLogFilePath('verifyPodfile', expect.getState().currentTestName),
- });
-
- assertions.assertVerifyJobExecuted(result, false);
- });
- });
- });
- describe('pull request synchronized', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'synchronize',
- };
- it('executes workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- verify: mocks.VERIFYPODFILE__VERIFY__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('verifyPodfile', expect.getState().currentTestName),
- });
-
- assertions.assertVerifyJobExecuted(result);
- });
- describe('actor is OSBotify', () => {
- it('does not execute workflow', async () => {
- const repoPath = mockGithub.repo.getPath('testVerifyPodfileWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- act = utils.setJobRunners(act, {verify: 'ubuntu-latest'}, workflowPath);
- const testMockSteps = {
- verify: mocks.VERIFYPODFILE__VERIFY__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'verifyPodfile.yml'),
- mockSteps: testMockSteps,
- actor: osbotifyActor,
- logFile: utils.getLogFilePath('verifyPodfile', expect.getState().currentTestName),
- });
-
- assertions.assertVerifyJobExecuted(result, false);
- });
- });
- });
-});
diff --git a/workflow_tests/verifySignedCommits.test.ts b/workflow_tests/verifySignedCommits.test.ts
deleted file mode 100644
index 3bf6c15ec1bb..000000000000
--- a/workflow_tests/verifySignedCommits.test.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import {MockGithub} from '@kie/mock-github';
-import path from 'path';
-import assertions from './assertions/verifySignedCommitsAssertions';
-import mocks from './mocks/verifySignedCommitsMocks';
-import ExtendedAct from './utils/ExtendedAct';
-import * as utils from './utils/utils';
-
-jest.setTimeout(90 * 1000);
-let mockGithub: MockGithub;
-
-const FILES_TO_COPY_INTO_TEST_REPO = [
- ...utils.deepCopy(utils.FILES_TO_COPY_INTO_TEST_REPO),
- {
- src: path.resolve(__dirname, '..', '.github', 'workflows', 'verifySignedCommits.yml'),
- dest: '.github/workflows/verifySignedCommits.yml',
- },
-];
-
-describe('test workflow verifySignedCommits', () => {
- const githubToken = 'dummy_github_token';
- const actor = 'Dummy Actor';
-
- beforeAll(() => {
- // in case of the tests being interrupted without cleanup the mock repo directory may be left behind
- // which breaks the next test run, this removes any possible leftovers
- utils.removeMockRepoDir();
- });
-
- beforeEach(async () => {
- // create a local repository and copy required files
- mockGithub = new MockGithub({
- repo: {
- testVerifySignedCommitsWorkflowRepo: {
- files: FILES_TO_COPY_INTO_TEST_REPO,
- },
- },
- });
-
- await mockGithub.setup();
- });
-
- afterEach(async () => {
- await mockGithub.teardown();
- });
- describe('pull request opened', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'opened',
- };
- it('test stub', async () => {
- const repoPath = mockGithub.repo.getPath('testVerifySignedCommitsWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifySignedCommits.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- verifySignedCommits: mocks.VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'verifySignedCommits.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('verifySignedCommits', expect.getState().currentTestName),
- });
-
- assertions.assertVerifySignedCommitsJobExecuted(result);
- });
- });
- describe('pull request synchronized', () => {
- const event = 'pull_request';
- const eventOptions = {
- action: 'synchronize',
- };
- it('test stub', async () => {
- const repoPath = mockGithub.repo.getPath('testVerifySignedCommitsWorkflowRepo') ?? '';
- const workflowPath = path.join(repoPath, '.github', 'workflows', 'verifySignedCommits.yml');
- let act = new ExtendedAct(repoPath, workflowPath);
- act = utils.setUpActParams(act, event, eventOptions, {}, githubToken);
- const testMockSteps = {
- verifySignedCommits: mocks.VERIFYSIGNEDCOMMITS__VERIFYSIGNEDCOMMITS__STEP_MOCKS,
- };
- const result = await act.runEvent(event, {
- workflowFile: path.join(repoPath, '.github', 'workflows', 'verifySignedCommits.yml'),
- mockSteps: testMockSteps,
- actor,
- logFile: utils.getLogFilePath('verifySignedCommits', expect.getState().currentTestName),
- });
-
- assertions.assertVerifySignedCommitsJobExecuted(result);
- });
- });
-});