Fix process (#10571)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2026-02-28 20:11:26 +05:00
committed by GitHub
parent c3758432bf
commit c1b8e77e16
9 changed files with 153 additions and 45 deletions
+24
View File
@@ -247,6 +247,14 @@
"safeForSimultaneousRushProcesses": true,
"shellCommand": "./common/scripts/docker.sh"
},
{
"commandKind": "global",
"name": "docker:patch",
"summary": "Build and push docker images with a custom version",
"description": "Allows building and pushing docker images with a manually specified version tag. Usage: rush docker:patch --version <version> [rush-args]",
"safeForSimultaneousRushProcesses": true,
"shellCommand": "./common/scripts/docker_patch.sh"
},
{
"commandKind": "global",
"name": "docker-server",
@@ -424,6 +432,22 @@
"longName": "--branch",
"description": "Force formatting of branch",
"associatedCommands": ["fast-format"]
},
{
"parameterKind": "string",
"argumentName": "VERSION",
"required": false,
"longName": "--version",
"description": "The version tag to use for docker images",
"associatedCommands": ["docker:patch"]
},
{
"parameterKind": "string",
"argumentName": "PLATFORM",
"required": false,
"longName": "--platform",
"description": "The target platform for docker build (e.g., linux/amd64). Defaults to linux/amd64.",
"associatedCommands": ["docker:patch"]
}
// {
// /**
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
version=$(git rev-parse HEAD)
version=${DOCKER_VERSION:-$(git rev-parse HEAD)}
# Check for cleanup flag from environment
cleanup=false
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# This script allows building and pushing docker images with a custom version tag.
# It can be run interactively or with the --version flag.
VERSION=""
PLATFORM="linux/amd64"
REMAINING_ARGS=()
while [[ $# -gt 0 ]]; do
case $1 in
--version)
VERSION="$2"
shift 2
;;
--platform)
PLATFORM="$2"
shift 2
;;
*)
REMAINING_ARGS+=("$1")
shift
;;
esac
done
if [ -z "$VERSION" ]; then
read -p "Enter version tag for docker images: " VERSION
fi
if [ -z "$VERSION" ]; then
echo "Error: Version tag is required."
exit 1
fi
export DOCKER_VERSION="$VERSION"
export DOCKER_EXTRA="--platform=$PLATFORM"
echo "Starting docker build and push for version: $DOCKER_VERSION ($PLATFORM)"
# We use 'node common/scripts/install-run-rush.js' to ensure we use the right rush version
node "$(dirname "$0")/install-run-rush.js" docker:build "${REMAINING_ARGS[@]}"
node "$(dirname "$0")/install-run-rush.js" docker:push "${REMAINING_ARGS[@]}"
echo "Docker patch completed for version: $DOCKER_VERSION"
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
version=$(git describe --tags --abbrev=0)
version=${DOCKER_VERSION:-$(git describe --tags --abbrev=0)}
rev_version=$(git rev-parse HEAD)
if [ "x$2" = "xstaging" ]
@@ -15,7 +15,9 @@
<script lang="ts">
import { Ref } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { Label } from '@hcengineering/ui'
import { State } from '@hcengineering/process'
import plugin from '../plugin'
export let value: Ref<State>
@@ -26,4 +28,6 @@
{#if currentState}
{currentState.title}
{:else if value === null}
<span class="opacity-50"><Label label={plugin.string.Started} /></span>
{/if}
+41 -31
View File
@@ -9,7 +9,8 @@ import core, {
type RefTo,
type ArrOf,
type ModelDb,
type Hierarchy
type Hierarchy,
type Type
} from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { type Process, type Transition } from '@hcengineering/process'
@@ -54,12 +55,50 @@ export function exportProcess (proc: Doc): {
processParams(tr.triggerParams, processDoc.masterTag, docs, required, m, h)
for (const action of tr.actions) {
processParams(action.params, processDoc.masterTag, docs, required, m, h)
if (action.results !== undefined) {
for (const res of action.results) {
processType(res.type, docs, required, m, h)
}
}
}
}
if (processDoc.context !== undefined) {
for (const key in processDoc.context) {
const ctx = processDoc.context[key as any]
if (ctx.type !== undefined) {
processType(ctx.type, docs, required, m, h)
}
}
}
if (processDoc.resultType !== undefined) {
processType(processDoc.resultType, docs, required, m, h)
}
return { docs, required }
}
function processType (type: Type<any>, docs: Doc[], required: Array<Ref<Class<Doc>>>, m: ModelDb, h: Hierarchy): void {
if (type._class === core.class.EnumOf) {
const enumRef = (type as EnumOf).of
const enumDoc = m.findObject(enumRef)
if (enumDoc !== undefined && !docs.some((d) => d._id === enumDoc._id)) {
docs.push(enumDoc)
}
}
if (type._class === core.class.RefTo) {
const to = (type as RefTo<Doc>).to
if (h.isDerived(to, card.class.Card) && !required.includes(to)) {
required.push(to)
}
}
if (type._class === core.class.ArrOf) {
const of = (type as ArrOf<Doc>).of
processType(of, docs, required, m, h)
}
}
function processParams (
params: Record<string, any> | undefined,
masterTag: Ref<MasterTag>,
@@ -85,36 +124,7 @@ function processParams (
}
const attr = h.findAttribute(masterTag, key)
if (attr !== undefined) {
const type = attr.type
if (type._class === core.class.EnumOf) {
const enumRef = (type as EnumOf).of
const enumDoc = m.findObject(enumRef)
if (enumDoc !== undefined && !docs.some((d) => d._id === enumDoc._id)) {
docs.push(enumDoc)
}
}
if (type._class === core.class.RefTo) {
const to = (type as RefTo<Doc>).to
if (h.isDerived(to, card.class.Card) && !required.includes(to)) {
required.push(to)
}
}
if (type._class === core.class.ArrOf) {
const of = (type as ArrOf<Doc>).of
if (of._class === core.class.EnumOf) {
const enumRef = (of as EnumOf).of
const enumDoc = m.findObject(enumRef)
if (enumDoc !== undefined && !docs.some((d) => d._id === enumDoc._id)) {
docs.push(enumDoc)
}
}
if (of._class === core.class.RefTo) {
const to = (of as RefTo<Doc>).to
if (h.isDerived(to, card.class.Card) && !required.includes(to)) {
required.push(to)
}
}
}
processType(attr.type, docs, required, m, h)
}
}
}
+14 -4
View File
@@ -21,6 +21,7 @@ import core, {
type Doc,
type DocumentQuery,
type DocumentUpdate,
findProperty,
generateId,
matchQuery,
type Ref,
@@ -564,7 +565,7 @@ export async function getSubProcessesUserInput (
const mockExecution: Execution = {
_id: generateId(),
process: processId,
currentState: initTransition.to,
currentState: null as any,
card,
rollback: [],
context,
@@ -629,7 +630,7 @@ export async function createExecution (
const mockExecution: Execution = {
_id: executionId,
process: _id,
currentState: initTransition.to,
currentState: null as any,
card,
rollback: [],
context: getEmptyContext(),
@@ -647,7 +648,7 @@ export async function createExecution (
space,
{
process: _id,
currentState: initTransition.to,
currentState: null as any,
card,
rollback: [],
context: result?.context ?? getEmptyContext(),
@@ -710,7 +711,16 @@ export function todoTranstionCheck (
context: Record<string, any>
): boolean {
if (params._id === undefined) return false
return context.todo?._id === params._id
return context.todo?._id === params._id && checkResult(context, params.result)
}
function checkResult (context: Record<string, any>, results: Record<string, any> | undefined): boolean {
if (results === undefined) return true
for (const [key, value] of Object.entries(results)) {
const res = findProperty([context as any], key, value)
if (res.length === 0) return false
}
return true
}
export function timeTransitionCheck (
@@ -408,9 +408,6 @@ export async function RunSubProcess (
const res: Tx[] = []
const resultContext: SuccessExecutionContext[] = []
const rollback: Tx[] = []
const initTransition = control.client
.getModel()
.findAllSync(process.class.Transition, { process: target._id, from: null })[0]
for (const _card of Array.isArray(card) ? card : [card]) {
if (target.parallelExecutionForbidden === true) {
const currentExecution = await control.client.findAll(process.class.Execution, {
@@ -432,7 +429,7 @@ export async function RunSubProcess (
execution.space,
{
process: processId,
currentState: initTransition.to,
currentState: null as any,
card: _card,
context,
status: ExecutionStatus.Active,
@@ -802,7 +799,7 @@ async function createExecution (
execution.space,
{
process: proc,
currentState: initTransition.to,
currentState: null as any,
card: _id,
rollback: [],
context: {},
+22 -3
View File
@@ -179,7 +179,8 @@ async function findTransitions (
process.class.Transition,
{
process: execution.process,
trigger: { $in: record.event }
from: null,
trigger: process.trigger.OnExecutionStart
},
{ sort: { rank: SortingOrder.Ascending } }
)
@@ -346,6 +347,17 @@ async function execute (execution: Execution, transition: Transition, control: P
control.ctx.info('Execution already in progress', { execution: execution._id, transition: transition._id })
return
}
const fresh = await control.client.findOne(process.class.Execution, { _id: execution._id })
if (fresh === undefined || fresh.currentState !== execution.currentState) {
control.ctx.info('Skipping stale transition execution', {
execution: execution._id,
expectedState: execution.currentState,
actualState: fresh?.currentState
})
return
}
activeExecutions.add(execution._id)
try {
await executeTransition(execution, transition, control)
@@ -497,13 +509,20 @@ async function executeTransition (
const apply = client.txFactory.createTxApplyIf(
core.space.Tx,
`${execution._id}_${transition._id}`,
[],
[{ _class: process.class.Execution, query: { _id: execution._id, currentState: execution.currentState } }],
[],
res as TxCUD<Doc>[],
'process',
true
)
await client.tx(apply)
const result = (await client.tx(apply)) as any
if (result.success === false) {
control.ctx.info('Transition apply failed (likely already processed)', {
execution: execution._id,
transition: transition._id
})
break
}
await sendEvent(control, execution, transition, card, isDone)
TxProcessor.applyUpdate(execution, executionUpdate)
if (execution.parentId !== undefined) {