Repository: nektos/act (language: go)

Issue:
Dynamic matrix with include: does nothing
### Bug report info

Tested with 0.2.26  and 2.2.27-dev
```
act version:            v0.2.27-dev
GOOS:                   darwin
GOARCH:                 amd64
NumCPU:                 4
Docker host:            DOCKER_HOST environment variable is unset/empty.
Sockets found:
	/var/run/docker.sock
Config files:
	/Users/jayvdb/.actrc:
		#-P self-hosted=catthehacker/ubuntu:act-latest
		-P self-hosted=ubuntu:jammy
		-P ubuntu-latest=catthehacker/ubuntu:act-latest
		-P ubuntu-22.04=catthehacker/ubuntu:act-22.04
		-P ubuntu-20.04=catthehacker/ubuntu:act-20.04
		-P ubuntu-18.04=catthehacker/ubuntu:act-18.04
		ubuntu-16.04=catthehacker/ubuntu:act-16.04
Build info:
	Go version:            go1.18.2
	Module path:           github.com/nektos/act
	Main version:          (devel)
	Main path:             github.com/nektos/act
	Main checksum:
	Build settings:
		-compiler:            gc
		CGO_ENABLED:          1
		CGO_CFLAGS:
		CGO_CPPFLAGS:
		CGO_CXXFLAGS:
		CGO_LDFLAGS:
		GOARCH:               amd64
		GOOS:                 darwin
		GOAMD64:              v1
		vcs:                  git
		vcs.revision:         bc0f09b9ea1df599011787f51d296bd793e7cfb5
		vcs.time:             2022-05-24T20:49:12Z
		vcs.modified:         false
Docker Engine:
	Engine version:        20.10.13
	Engine runtime:        runc
	Cgroup version:        2
	Cgroup driver:         cgroupfs
	Storage driver:        overlay2
	Registry URI:          https://index.docker.io/v1/
	OS:                    Docker Desktop
	OS type:               linux
	OS version:
	OS arch:               x86_64
	OS kernel:             5.10.104-linuxkit
	OS CPU:                2
	OS memory:             7960 MB
	Security options:
		name=seccomp,profile=default
		name=cgroupns
```

```
act version:            0.2.26
GOOS:                   darwin
GOARCH:                 amd64
NumCPU:                 4
Docker host:            DOCKER_HOST environment variable is unset/empty.
Sockets found:
	/var/run/docker.sock
Config files:
	/Users/jayvdb/.actrc:
		#-P self-hosted=catthehacker/ubuntu:act-latest
		-P self-hosted=ubuntu:jammy
		-P ubuntu-latest=catthehacker/ubuntu:act-latest
		-P ubuntu-22.04=catthehacker/ubuntu:act-22.04
		-P ubuntu-20.04=catthehacker/ubuntu:act-20.04
		-P ubuntu-18.04=catthehacker/ubuntu:act-18.04
		ubuntu-16.04=catthehacker/ubuntu:act-16.04
Docker Engine:
	Engine version:        20.10.13
	Engine runtime:        runc
	Cgroup version:        2
	Cgroup driver:         cgroupfs
	Storage driver:        overlay2
	Registry URI:          https://index.docker.io/v1/
	OS:                    Docker Desktop
	OS type:               linux
	OS version:
	OS arch:               x86_64
	OS kernel:             5.10.104-linuxkit
	OS CPU:                2
	OS memory:             7960 MB
	Security options:
		name=seccomp,profile=default
		name=cgroupns
```

### Command used with act

```sh
act -j job2
```


### Describe issue

The example is here https://github.community/t/how-to-conditionally-include-exclude-items-in-matrix-eg-based-on-branch/16853/7
`act -j job2` will run `job1` but doesnt run job2.

### Link to GitHub repository

_No response_

### Workflow content

```yml
name: build
on: push
jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
    - id: set-matrix
      run: echo "::set-output name=matrix::{\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}"
  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{fromJson(needs.job1.outputs.matrix)}}
    steps:
    - run: build
```


### Relevant log output

```sh
% ~/go/bin/act -j job2
[bug/job1] 🚀  Start image=catthehacker/ubuntu:act-latest
[bug/job1]   🐳  docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=false
[bug/job1]   🐳  docker create image=catthehacker/ubuntu:act-latest platform= entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[bug/job1]   🐳  docker run image=catthehacker/ubuntu:act-latest platform= entrypoint=["/usr/bin/tail" "-f" "/dev/null"] cmd=[]
[bug/job1]   🐳  docker exec cmd=[mkdir -m 0777 -p /var/run/act] user=root workdir=
[bug/job1] ⭐  Run echo "::set-output name=matrix::{\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}"
[bug/job1]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/set-matrix] user= workdir=
[bug/job1]   ⚙  ::set-output:: matrix={"include":[{"project":"foo","config":"Debug"},{"project":"bar","config":"Release"}]}
[bug/job1]   ✅  Success - echo "::set-output name=matrix::{\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}"
```
```


### Additional information

_No response_
act silently stopping
### Bug report info

```plain text
juliangro@x299-desktop:~/Software/act$ ./act --bug-report
act version:            0.2.26
GOOS:                   linux
GOARCH:                 amd64
NumCPU:                 12
Docker host:            DOCKER_HOST environment variable is unset/empty.
Sockets found:
	/var/run/docker.sock
Config files:           
	/home/juliangro/.actrc:
		-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest
		-P ubuntu-20.04=ghcr.io/catthehacker/ubuntu:act-20.04
		-P ubuntu-18.04=ghcr.io/catthehacker/ubuntu:act-18.04
Docker Engine:
	Engine version:        20.10.14+dfsg1
	Engine runtime:        runc
	Cgroup version:        2
	Cgroup driver:         systemd
	Storage driver:        btrfs
	Registry URI:          https://index.docker.io/v1/
	OS:                    Debian GNU/Linux bookworm/sid
	OS type:               linux
	OS version:            
	OS arch:               x86_64
	OS kernel:             5.18.0-1-amd64
	OS CPU:                12
	OS memory:             31811 MB
	Security options:
		name=apparmor
		name=seccomp,profile=default
		name=cgroupns

juliangro@x299-desktop:~/Software/act$
```


### Command used with act

```sh
./act -W /home/juliangro/git/temp/project-athena-docker/.github/workflows/master_docker_build.yml -C /home/juliangro/git/temp/project-athena-docker/ -v --detect-event
```


### Describe issue

Act just silently stops when trying to run my workflow.
As you can see in the debug output it just says "false" without any meaningfull information.

### Link to GitHub repository

_No response_

### Workflow content

```yml
name: Master CI Docker Server Build

on:
  push
#  push:
#    branches:
#      - master

env:
  BUILD_TYPE: Release
  BUILD_NUMBER: ${{ github.run_number }}
  CI_BUILD: Github
  GIT_COMMIT: ${{ github.sha }}
  RELEASE_TYPE: PRODUCTION
  RELEASE_NUMBER: ${{ github.run_number }}
  STABLE_BUILD: 0
  UPLOAD_BUCKET: overte-public
  UPLOAD_REGION: fra1
  UPLOAD_ENDPOINT: "https://fra1.digitaloceanspaces.com"
  # Use Docker BuildKit backend
  DOCKER_BUILDKIT: 1


jobs:
  build:
    strategy:
      matrix:
        include:
          - os: ubuntu-20.04
            apt-dependencies: docker.io
          # Do not change the names of self-hosted runners without knowing what you are doing, as they correspond to labels that have to be set on the runner.
          #~ - os: self-hosted_debian-11_aarch64
            #~ build_type: full
            #~ apt-dependencies: docker.io
      fail-fast: false
    runs-on: ${{matrix.os}}
    steps:
    - name: Report Build Number
      shell: bash
      run: |

        echo "Build number: $BUILD_NUMBER"

    - uses: actions/checkout@v1
      with:
        submodules: false
        fetch-depth: 1

    - name: Install dependencies
      shell: bash
      run: |
      
          echo "Updating apt repository index"
          sudo apt update || exit 1

          echo "Installing apt packages"
          sudo apt install -y ${{ matrix.apt-dependencies }} || exit 1

    - name: Create Docker environment
      shell: bash
      run: mkdir build

    - name: Start Docker build container
      working-directory: ${{runner.workspace}}
      run: docker build -f tools/ci-scripts/docker_package/Dockerfile_build .
```


### Relevant log output

```sh
juliangro@x299-desktop:~/Software/act$ ./act -W /home/juliangro/git/temp/project-athena-docker/.github/workflows/master_docker_build.yml -C /home/juliangro/git/temp/project-athena-docker/ -v --detect-event
DEBU[0000] Loading environment from /home/juliangro/git/temp/project-athena-docker/.env 
DEBU[0000] Loading secrets from /home/juliangro/git/temp/project-athena-docker/.secrets 
DEBU[0000] Loading workflow '/home/juliangro/git/temp/project-athena-docker/.github/workflows/master_docker_build.yml' 
DEBU[0000] Reading workflow '/home/juliangro/git/temp/project-athena-docker/.github/workflows/master_docker_build.yml' 
DEBU[0000] Using detected workflow event: push          
DEBU[0000] Planning event: push                         
DEBU[0000] Loading slug from git directory '/home/juliangro/git/temp/project-athena-docker/.git' 
DEBU[0000] Loading revision from git directory '/home/juliangro/git/temp/project-athena-docker/.git' 
DEBU[0000] Found revision: 581aa24a7890d44654e4b84a9cfe3686f63653fd 
DEBU[0000] HEAD points to '581aa24a7890d44654e4b84a9cfe3686f63653fd' 
DEBU[0000] using github ref: refs/heads/docker_experiment 
DEBU[0000] Found revision: 581aa24a7890d44654e4b84a9cfe3686f63653fd 
DEBU[0000] Loading slug from git directory '/home/juliangro/git/temp/project-athena-docker/.git' 
DEBU[0000] Loading revision from git directory '/home/juliangro/git/temp/project-athena-docker/.git' 
DEBU[0000] Found revision: 581aa24a7890d44654e4b84a9cfe3686f63653fd 
DEBU[0000] HEAD points to '581aa24a7890d44654e4b84a9cfe3686f63653fd' 
DEBU[0000] using github ref: refs/heads/docker_experiment 
DEBU[0000] Found revision: 581aa24a7890d44654e4b84a9cfe3686f63653fd 
DEBU[0000] false                                        
juliangro@x299-desktop:~/Software/act$
```


### Additional information

_No response_


Discussion / hints:

Fix patch:
diff --git a/pkg/model/workflow.go b/pkg/model/workflow.go
index 7d0e9e91eb9..ab370436d9b 100644
--- a/pkg/model/workflow.go
+++ b/pkg/model/workflow.go
@@ -224,26 +224,37 @@ func (j *Job) GetMatrixes() []map[string]interface{} {
 
 		if m := j.Matrix(); m != nil {
 			includes := make([]map[string]interface{}, 0)
+			extraIncludes := make([]map[string]interface{}, 0)
 			for _, v := range m["include"] {
 				switch t := v.(type) {
 				case []interface{}:
 					for _, i := range t {
 						i := i.(map[string]interface{})
+						extraInclude := true
 						for k := range i {
 							if _, ok := m[k]; ok {
 								includes = append(includes, i)
+								extraInclude = false
 								break
 							}
 						}
+						if extraInclude {
+							extraIncludes = append(extraIncludes, i)
+						}
 					}
 				case interface{}:
 					v := v.(map[string]interface{})
+					extraInclude := true
 					for k := range v {
 						if _, ok := m[k]; ok {
 							includes = append(includes, v)
+							extraInclude = false
 							break
 						}
 					}
+					if extraInclude {
+						extraIncludes = append(extraIncludes, v)
+					}
 				}
 			}
 			delete(m, "include")
@@ -274,9 +285,27 @@ func (j *Job) GetMatrixes() []map[string]interface{} {
 				matrixes = append(matrixes, matrix)
 			}
 			for _, include := range includes {
+				matched := false
+				for _, matrix := range matrixes {
+					if commonKeysMatch2(matrix, include, m) {
+						matched = true
+						log.Debugf("Adding include values '%v' to existing entry", include)
+						for k, v := range include {
+							matrix[k] = v
+						}
+					}
+				}
+				if !matched {
+					extraIncludes = append(extraIncludes, include)
+				}
+			}
+			for _, include := range extraIncludes {
 				log.Debugf("Adding include '%v'", include)
 				matrixes = append(matrixes, include)
 			}
+			if len(matrixes) == 0 {
+				matrixes = append(matrixes, make(map[string]interface{}))
+			}
 		} else {
 			matrixes = append(matrixes, make(map[string]interface{}))
 		}
@@ -295,6 +324,16 @@ func commonKeysMatch(a map[string]interface{}, b map[string]interface{}) bool {
 	return true
 }
 
+func commonKeysMatch2(a map[string]interface{}, b map[string]interface{}, m map[string][]interface{}) bool {
+	for aKey, aVal := range a {
+		_, useKey := m[aKey]
+		if bVal, ok := b[aKey]; useKey && ok && !reflect.DeepEqual(aVal, bVal) {
+			return false
+		}
+	}
+	return true
+}
+
 // ContainerSpec is the specification of the container to use for the job
 type ContainerSpec struct {
 	Image       string            `yaml:"image"`


Test patch:
diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go
index f15d570b2a0..6d3b307f5e4 100644
--- a/pkg/model/workflow_test.go
+++ b/pkg/model/workflow_test.go
@@ -247,6 +247,7 @@ func TestReadWorkflow_Strategy(t *testing.T) {
 			{"datacenter": "site-c", "node-version": "14.x", "site": "staging"},
 			{"datacenter": "site-c", "node-version": "16.x", "site": "staging"},
 			{"datacenter": "site-d", "node-version": "16.x", "site": "staging"},
+			{"php-version": 5.4},
 			{"datacenter": "site-a", "node-version": "10.x", "site": "prod"},
 			{"datacenter": "site-b", "node-version": "12.x", "site": "dev"},
 		},
diff --git a/pkg/runner/testdata/evalmatrix/push.yml b/pkg/runner/testdata/evalmatrix/push.yml
index 94e9741e9df..dd742ecd116 100644
--- a/pkg/runner/testdata/evalmatrix/push.yml
+++ b/pkg/runner/testdata/evalmatrix/push.yml
@@ -15,4 +15,65 @@ jobs:
         echo $MATRIX
         exit ${{matrix.A && '0' || '1'}}
       env:
-        MATRIX: ${{toJSON(matrix)}}
\ No newline at end of file
+        MATRIX: ${{toJSON(matrix)}}
+  _additionalInclude_0:
+    strategy:
+      matrix:
+        include:
+        - def: val
+    runs-on: ubuntu-latest
+    steps:
+    - name: Check if the matrix key A exists
+      run: |
+        echo $MATRIX
+        exit ${{matrix.def == 'val' && '0' || '1'}}
+      env:
+        MATRIX: ${{toJSON(matrix)}}
+    - run: |
+        echo "::set-output name=result::success"
+      id: result
+    outputs:
+      result: ${{ steps.result.outputs.result }}
+  _additionalInclude_1:
+    needs: _additionalInclude_0
+    if: always()
+    runs-on: ubuntu-latest
+    steps:
+    - name: Check if the matrix key A exists
+      run: |
+        echo $MATRIX
+        exit ${{needs._additionalInclude_0.outputs.result == 'success' && '0' || '1'}}
+  _additionalProperties_0:
+    strategy:
+      matrix:
+        x:
+        - 0
+        y:
+        - 0
+        z:
+        - 0
+        include:
+        - def: val
+          z: 0
+    runs-on: ubuntu-latest
+    steps:
+    - name: Check if the matrix key A exists
+      run: |
+        echo $MATRIX
+        exit ${{matrix.def == 'val' && matrix.x == 0 && matrix.y == 0 && matrix.z == 0 && '0' || '1'}}
+      env:
+        MATRIX: ${{toJSON(matrix)}}
+    - run: |
+        echo "::set-output name=result::success"
+      id: result
+    outputs:
+      result: ${{ steps.result.outputs.result }}
+  _additionalProperties_1:
+    needs: _additionalProperties_0
+    if: always()
+    runs-on: ubuntu-latest
+    steps:
+    - name: Check if the matrix key A exists
+      run: |
+        echo $MATRIX
+        exit ${{needs._additionalProperties_0.outputs.result == 'success' && '0' || '1'}}