<commit_before>package exportentities

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/fsamin/go-dump"

	"github.com/ovh/cds/sdk"
)

// Workflow is the "as code" representation of a sdk.Workflow
type Workflow struct {
	Name    string `json:"name" yaml:"name"`
	Version string `json:"version,omitempty" yaml:"version,omitempty"`
	// This will be filled for complex workflows
	Workflow map[string]NodeEntry   `json:"workflow,omitempty" yaml:"workflow,omitempty"`
	Hooks    map[string][]HookEntry `json:"hooks,omitempty" yaml:"hooks,omitempty"`
	// This will be filled for simple workflows
	DependsOn           []string                    `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
	Conditions          *sdk.WorkflowNodeConditions `json:"conditions,omitempty" yaml:"conditions,omitempty"`
	When                []string                    `json:"when,omitempty" yaml:"when,omitempty"` //This is use only for manual and success condition
	PipelineName        string                      `json:"pipeline,omitempty" yaml:"pipeline,omitempty"`
	Payload             map[string]interface{}      `json:"payload,omitempty" yaml:"payload,omitempty"`
	Parameters          map[string]string           `json:"parameters,omitempty" yaml:"parameters,omitempty"`
	ApplicationName     string                      `json:"application,omitempty" yaml:"application,omitempty"`
	EnvironmentName     string                      `json:"environment,omitempty" yaml:"environment,omitempty"`
	ProjectPlatformName string                      `json:"platform,omitempty" yaml:"platform,omitempty"`
	PipelineHooks       []HookEntry                 `json:"pipeline_hooks,omitempty" yaml:"pipeline_hooks,omitempty"`
	Permissions         map[string]int              `json:"permissions,omitempty" yaml:"permissions,omitempty"`
	Metadata            map[string]string           `json:"metadata,omitempty" yaml:"metadata,omitempty" db:"-"`
	PurgeTags           []string                    `json:"purge_tags,omitempty" yaml:"purge_tags,omitempty" db:"-"`
	HistoryLength       int64                       `json:"history_length,omitempty" yaml:"history_length,omitempty" db:"-"`
}

// NodeEntry represents a node as code
type NodeEntry struct {
	ID                  int64                       `json:"-" yaml:"-"`
	DependsOn           []string                    `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
	Conditions          *sdk.WorkflowNodeConditions `json:"conditions,omitempty" yaml:"conditions,omitempty"`
	When                []string                    `json:"when,omitempty" yaml:"when,omitempty"` //This is use only for manual and success condition
	PipelineName        string                      `json:"pipeline,omitempty" yaml:"pipeline,omitempty"`
	ApplicationName     string                      `json:"application,omitempty" yaml:"application,omitempty"`
	EnvironmentName     string                      `json:"environment,omitempty" yaml:"environment,omitempty"`
	ProjectPlatformName string                      `json:"platform,omitempty" yaml:"platform,omitempty"`
	OneAtATime          *bool                       `json:"one_at_a_time,omitempty" yaml:"one_at_a_time,omitempty"`
	Payload             map[string]interface{}      `json:"payload,omitempty" yaml:"payload,omitempty"`
	Parameters          map[string]string           `json:"parameters,omitempty" yaml:"parameters,omitempty"`
}

// HookEntry represents a hook as code
type HookEntry struct {
	Model  string            `json:"type,omitempty" yaml:"type,omitempty"`
	Ref    string            `json:"ref,omitempty" yaml:"ref,omitempty"`
	Config map[string]string `json:"config,omitempty" yaml:"config,omitempty"`
}

// WorkflowVersion is the type for the version
type WorkflowVersion string

// There are the supported versions
const (
	WorkflowVersion1 = "v1.0"
)

//NewWorkflow creates a new exportable workflow
func NewWorkflow(w sdk.Workflow, withPermission bool) (Workflow, error) {
	exportedWorkflow := Workflow{}
	exportedWorkflow.Name = w.Name
	exportedWorkflow.Version = WorkflowVersion1
	exportedWorkflow.Workflow = map[string]NodeEntry{}
	exportedWorkflow.Hooks = map[string][]HookEntry{}
	if len(w.Metadata) > 0 {
		exportedWorkflow.Metadata = make(map[string]string, len(w.Metadata))
		for k, v := range w.Metadata {
			exportedWorkflow.Metadata[k] = v
		}
	}

	if w.HistoryLength > 0 {
		exportedWorkflow.HistoryLength = w.HistoryLength
	} else {
		exportedWorkflow.HistoryLength = 20
	}

	exportedWorkflow.PurgeTags = w.PurgeTags
	nodes := w.Nodes(false)

	if withPermission {
		exportedWorkflow.Permissions = make(map[string]int, len(w.Groups))
		for _, p := range w.Groups {
			exportedWorkflow.Permissions[p.Group.Name] = p.Permission
		}
	}

	var craftNodeEntry = func(n *sdk.WorkflowNode) (NodeEntry, error) {
		entry := NodeEntry{}

		ancestorIDs := n.Ancestors(&w, false)
		ancestors := make([]string, 0, len(ancestorIDs))
		for _, aID := range ancestorIDs {
			a := w.GetNode(aID)
			if a == nil {
				return entry, sdk.ErrWorkflowNodeNotFound
			}
			ancestors = append(ancestors, a.Name)
		}

		entry.DependsOn = ancestors
		entry.PipelineName = n.Pipeline.Name
		conditions := []sdk.WorkflowNodeCondition{}
		for _, c := range n.Context.Conditions.PlainConditions {
			if c.Operator == sdk.WorkflowConditionsOperatorEquals &&
				c.Value == "Success" &&
				c.Variable == "cds.status" {
				entry.When = append(entry.When, "success")
			} else if c.Operator == sdk.WorkflowConditionsOperatorEquals &&
				c.Value == "true" &&
				c.Variable == "cds.manual" {
				entry.When = append(entry.When, "manual")
			} else {
				conditions = append(conditions, c)
			}
		}

		if len(conditions) > 0 || n.Context.Conditions.LuaScript != "" {
			entry.Conditions = &sdk.WorkflowNodeConditions{
				PlainConditions: conditions,
				LuaScript:       n.Context.Conditions.LuaScript,
			}
		}

		if n.Context.Application != nil {
			entry.ApplicationName = n.Context.Application.Name<commit_msg>fix (api): sort depends on (#2816)<commit_after>package exportentities

import (
	"fmt"
	"math/rand"
	"sort"
	"time"

	"github.com/fsamin/go-dump"

	"github.com/ovh/cds/sdk"
)

// Workflow is the "as code" representation of a sdk.Workflow
type Workflow struct {
	Name    string `json:"name" yaml:"name"`
	Version string `json:"version,omitempty" yaml:"version,omitempty"`
	// This will be filled for complex workflows
	Workflow map[string]NodeEntry   `json:"workflow,omitempty" yaml:"workflow,omitempty"`
	Hooks    map[string][]HookEntry `json:"hooks,omitempty" yaml:"hooks,omitempty"`
	// This will be filled for simple workflows
	DependsOn           []string                    `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
	Conditions          *sdk.WorkflowNodeConditions `json:"conditions,omitempty" yaml:"conditions,omitempty"`
	When                []string                    `json:"when,omitempty" yaml:"when,omitempty"` //This is use only for manual and success condition
	PipelineName        string                      `json:"pipeline,omitempty" yaml:"pipeline,omitempty"`
	Payload             map[string]interface{}      `json:"payload,omitempty" yaml:"payload,omitempty"`
	Parameters          map[string]string           `json:"parameters,omitempty" yaml:"parameters,omitempty"`
	ApplicationName     string                      `json:"application,omitempty" yaml:"application,omitempty"`
	EnvironmentName     string                      `json:"environment,omitempty" yaml:"environment,omitempty"`
	ProjectPlatformName string                      `json:"platform,omitempty" yaml:"platform,omitempty"`
	PipelineHooks       []HookEntry                 `json:"pipeline_hooks,omitempty" yaml:"pipeline_hooks,omitempty"`
	Permissions         map[string]int              `json:"permissions,omitempty" yaml:"permissions,omitempty"`
	Metadata            map[string]string           `json:"metadata,omitempty" yaml:"metadata,omitempty" db:"-"`
	PurgeTags           []string                    `json:"purge_tags,omitempty" yaml:"purge_tags,omitempty" db:"-"`
	HistoryLength       int64                       `json:"history_length,omitempty" yaml:"history_length,omitempty" db:"-"`
}

// NodeEntry represents a node as code
type NodeEntry struct {
	ID                  int64                       `json:"-" yaml:"-"`
	DependsOn           []string                    `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
	Conditions          *sdk.WorkflowNodeConditions `json:"conditions,omitempty" yaml:"conditions,omitempty"`
	When                []string                    `json:"when,omitempty" yaml:"when,omitempty"` //This is use only for manual and success condition
	PipelineName        string                      `json:"pipeline,omitempty" yaml:"pipeline,omitempty"`
	ApplicationName     string                      `json:"application,omitempty" yaml:"application,omitempty"`
	EnvironmentName     string                      `json:"environment,omitempty" yaml:"environment,omitempty"`
	ProjectPlatformName string                      `json:"platform,omitempty" yaml:"platform,omitempty"`
	OneAtATime          *bool                       `json:"one_at_a_time,omitempty" yaml:"one_at_a_time,omitempty"`
	Payload             map[string]interface{}      `json:"payload,omitempty" yaml:"payload,omitempty"`
	Parameters          map[string]string           `json:"parameters,omitempty" yaml:"parameters,omitempty"`
}

// HookEntry represents a hook as code
type HookEntry struct {
	Model  string            `json:"type,omitempty" yaml:"type,omitempty"`
	Ref    string            `json:"ref,omitempty" yaml:"ref,omitempty"`
	Config map[string]string `json:"config,omitempty" yaml:"config,omitempty"`
}

// WorkflowVersion is the type for the version
type WorkflowVersion string

// There are the supported versions
const (
	WorkflowVersion1 = "v1.0"
)

//NewWorkflow creates a new exportable workflow
func NewWorkflow(w sdk.Workflow, withPermission bool) (Workflow, error) {
	exportedWorkflow := Workflow{}
	exportedWorkflow.Name = w.Name
	exportedWorkflow.Version = WorkflowVersion1
	exportedWorkflow.Workflow = map[string]NodeEntry{}
	exportedWorkflow.Hooks = map[string][]HookEntry{}
	if len(w.Metadata) > 0 {
		exportedWorkflow.Metadata = make(map[string]string, len(w.Metadata))
		for k, v := range w.Metadata {
			exportedWorkflow.Metadata[k] = v
		}
	}

	if w.HistoryLength > 0 {
		exportedWorkflow.HistoryLength = w.HistoryLength
	} else {
		exportedWorkflow.HistoryLength = 20
	}

	exportedWorkflow.PurgeTags = w.PurgeTags
	nodes := w.Nodes(false)

	if withPermission {
		exportedWorkflow.Permissions = make(map[string]int, len(w.Groups))
		for _, p := range w.Groups {
			exportedWorkflow.Permissions[p.Group.Name] = p.Permission
		}
	}

	var craftNodeEntry = func(n *sdk.WorkflowNode) (NodeEntry, error) {
		entry := NodeEntry{}

		ancestorIDs := n.Ancestors(&w, false)
		ancestors := make([]string, 0, len(ancestorIDs))
		for _, aID := range ancestorIDs {
			a := w.GetNode(aID)
			if a == nil {
				return entry, sdk.ErrWorkflowNodeNotFound
			}
			ancestors = append(ancestors, a.Name)
		}

		sort.Strings(ancestors)
		entry.DependsOn = ancestors
		entry.PipelineName = n.Pipeline.Name
		conditions := []sdk.WorkflowNodeCondition{}
		for _, c := range n.Context.Conditions.PlainConditions {
			if c.Operator == sdk.WorkflowConditionsOperatorEquals &&
				c.Value == "Success" &&
				c.Variable == "cds.status" {
				entry.When = append(entry.When, "success")
			} else if c.Operator == sdk.WorkflowConditionsOperatorEquals &&
				c.Value == "true" &&
				c.Variable == "cds.manual" {
				entry.When = append(entry.When, "manual")
			} else {
				conditions = append(conditions, c)
			}
		}

		if len(conditions) > 0 || n.Context.Conditions.LuaScript != "" {
			entry.Conditions = &sdk.WorkflowNodeConditions{
				PlainConditions: conditions,
				LuaScript:       n.Context.Conditions.LuaScript,
			}
		}

		if n.Context.Application != nil {
			entry.ApplicationName = n.Context.Application.Name
{'fraction_non_alphanumeric': 0.11825985498791566, 'fraction_numerical': 0.0026668889074089506, 'mean_word_length': 3.2704626334519573, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5913130', 'n_tokens_mistral': 3674, 'n_tokens_neox': 3384, 'n_words': 722}