Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package forgejo-runner for openSUSE:Factory 
checked in at 2025-12-25 19:57:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/forgejo-runner (Old)
 and      /work/SRC/openSUSE:Factory/.forgejo-runner.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "forgejo-runner"

Thu Dec 25 19:57:45 2025 rev:37 rq:1324386 version:12.3.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/forgejo-runner/forgejo-runner.changes    
2025-12-22 22:52:47.209793275 +0100
+++ /work/SRC/openSUSE:Factory/.forgejo-runner.new.1928/forgejo-runner.changes  
2025-12-25 19:58:01.112151935 +0100
@@ -1,0 +2,10 @@
+Thu Dec 25 01:23:30 UTC 2025 - Richard Rahl <[email protected]>
+
+- Update to version 12.3.1:
+  * feat(jobparser): separate the concept of an instance & external reusable
+    workflow
+  * fix: second-layer reusable workflows losing their inputs when expanded
+- remove basic version check, as upstream most of the time forgets updating
+  that
+
+-------------------------------------------------------------------

Old:
----
  forgejo-runner-12.3.0.obscpio

New:
----
  forgejo-runner-12.3.1.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ forgejo-runner.spec ++++++
--- /var/tmp/diff_new_pack.QnEcko/_old  2025-12-25 19:58:02.144193811 +0100
+++ /var/tmp/diff_new_pack.QnEcko/_new  2025-12-25 19:58:02.148193973 +0100
@@ -17,9 +17,8 @@
 
 
 %define services %{name}.service
-
 Name:           forgejo-runner
-Version:        12.3.0
+Version:        12.3.1
 Release:        0
 Summary:        Daemon that connects to a Forgejo instance and runs CI jobs
 License:        GPL-3.0-or-later
@@ -112,10 +111,6 @@
 install    -m 0640 /dev/null   %{buildroot}%{_sysconfdir}/%{name}/runners
 install -D -m 0750 -d          %{buildroot}%{_localstatedir}/lib/%{name}
 
-# this update forgot to change the version, so disable for >12.1.1, enable 
when update
-#%%check
-#bin/%{name} --version | grep %{version}
-
 %pre
 %service_add_pre %{services}
 

++++++ _service ++++++
--- /var/tmp/diff_new_pack.QnEcko/_old  2025-12-25 19:58:02.216196733 +0100
+++ /var/tmp/diff_new_pack.QnEcko/_new  2025-12-25 19:58:02.228197220 +0100
@@ -2,7 +2,7 @@
   <service name="obs_scm" mode="manual">
     <param name="url">https://code.forgejo.org/forgejo/runner</param>
     <param name="scm">git</param>
-    <param name="revision">refs/tags/v12.3.0</param>
+    <param name="revision">refs/tags/v12.3.1</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">disable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ forgejo-runner-12.3.0.obscpio -> forgejo-runner-12.3.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/forgejo-runner-12.3.0/act/jobparser/jobparser.go 
new/forgejo-runner-12.3.1/act/jobparser/jobparser.go
--- old/forgejo-runner-12.3.0/act/jobparser/jobparser.go        2025-12-21 
17:32:28.000000000 +0100
+++ new/forgejo-runner-12.3.1/act/jobparser/jobparser.go        2025-12-24 
17:06:29.000000000 +0100
@@ -120,7 +120,7 @@
        }
 
        // Expand reusable workflows `uses:...` into inner jobs:
-       if pc.localWorkflowFetcher != nil || pc.remoteWorkflowFetcher != nil {
+       if pc.localWorkflowFetcher != nil || pc.instanceWorkflowFetcher != nil 
|| pc.externalWorkflowFetcher != nil {
                newJobs, err := expandReusableWorkflows(postMatrixJobs, 
validate, incompleteMatrix, options, pc, results)
                if err != nil {
                        return nil, err
@@ -340,84 +340,111 @@
                        continue
                }
 
-               workflowJob := bothJobs.workflowJob
-
-               jobType, err := workflowJob.Type()
+               reusableWorkflow, err := tryFetchReusableWorkflow(bothJobs, pc)
                if err != nil {
                        return nil, err
+               } else if reusableWorkflow == nil {
+                       // Not a reusable workflow to expand.
+                       continue
                }
-               var reusableWorkflow []byte
-               if jobType == model.JobTypeReusableWorkflowLocal && 
pc.localWorkflowFetcher != nil {
-                       contents, err := 
pc.localWorkflowFetcher(bothJobs.jobParserJob, workflowJob.Uses)
-                       if err != nil {
-                               if errors.Is(err, 
ErrUnsupportedReusableWorkflowFetch) {
-                                       // Skip workflow expansion.
-                                       continue
-                               }
-                               return nil, fmt.Errorf("unable to read local 
workflow %q: %w", workflowJob.Uses, err)
+
+               // If we encounter an InvalidJobOutputReferencedError error, 
we'll know that this is caused by a `with:`
+               // clause referencing a job output that isn't present yet.  In 
this case, don't expand the job, but provide
+               // the error back in `bothJobTypes` so that it can be returned 
in the `SingleWorkflow`.
+               var withInvalidJobReference 
*exprparser.InvalidJobOutputReferencedError
+               // Same type of error, but for accessing an invalid matrix 
during `with:`.
+               var withInvalidMatrixReference 
*exprparser.InvalidMatrixDimensionReferencedError
+
+               workflowParent := generateWorkflowCallID(pc.parentUniqueID, 
bothJobs.id, bothJobs.matrix)
+               bothJobs.workflowCallID = workflowParent
+
+               newJobs, err := expandReusableWorkflow(reusableWorkflow, 
validate, options, pc, jobResults, bothJobs.matrix, bothJobs)
+               if err != nil {
+                       errors.As(err, &withInvalidJobReference)
+                       errors.As(err, &withInvalidMatrixReference)
+                       if withInvalidJobReference == nil && 
withInvalidMatrixReference == nil {
+                               return nil, fmt.Errorf("error expanding 
reusable workflow %q: %v", bothJobs.workflowJob.Uses, err)
                        }
-                       reusableWorkflow = contents
                }
-               if jobType == model.JobTypeReusableWorkflowRemote && 
pc.remoteWorkflowFetcher != nil {
-                       parsed, err := 
model.ParseRemoteReusableWorkflow(workflowJob.Uses)
-                       if err != nil {
-                               return nil, fmt.Errorf("unable to parse `uses: 
%q` as a valid reusable workflow: %w", workflowJob.Uses, err)
-                       }
-                       contents, err := 
pc.remoteWorkflowFetcher(bothJobs.jobParserJob, parsed)
-                       if err != nil {
-                               if errors.Is(err, 
ErrUnsupportedReusableWorkflowFetch) {
-                                       // Skip workflow expansion.
-                                       continue
-                               }
-                               return nil, fmt.Errorf("unable to read remote 
workflow %q: %w", workflowJob.Uses, err)
+
+               if withInvalidJobReference == nil && withInvalidMatrixReference 
== nil {
+                       // Append the inner jobs' IDs to the `needs` of the 
parent job.
+                       additionalNeeds := make([]string, len(newJobs))
+                       for i, b := range newJobs {
+                               additionalNeeds[i] = b.id
                        }
-                       reusableWorkflow = contents
+                       callerNeeds := bothJobs.jobParserJob.Needs()
+                       callerNeeds = append(callerNeeds, additionalNeeds...)
+                       _ = bothJobs.jobParserJob.RawNeeds.Encode(callerNeeds)
+
+                       // The calling job will still exist in order to act as 
a `sentinel` for `needs` job ordering & output
+                       // access. We'll take away the job's content to ensure 
nothing is actually executed.
+                       _ = bothJobs.jobParserJob.If.Encode(false)
+                       bothJobs.jobParserJob.Uses = ""
+                       bothJobs.jobParserJob.With = nil
+               } else {
+                       // Retain all the original data of the job until it's 
really expanded, with its inputs, later
+                       bothJobs.withInvalidJobReference = 
withInvalidJobReference
+                       bothJobs.withInvalidMatrixReference = 
withInvalidMatrixReference
                }
-               if reusableWorkflow != nil {
-                       // If we encounter an InvalidJobOutputReferencedError 
error, we'll know that this is caused by a `with:`
-                       // clause referencing a job output that isn't present 
yet.  In this case, don't expand the job, but provide
-                       // the error back in `bothJobTypes` so that it can be 
returned in the `SingleWorkflow`.
-                       var withInvalidJobReference 
*exprparser.InvalidJobOutputReferencedError
-                       // Same type of error, but for accessing an invalid 
matrix during `with:`.
-                       var withInvalidMatrixReference 
*exprparser.InvalidMatrixDimensionReferencedError
 
-                       workflowParent := 
generateWorkflowCallID(pc.parentUniqueID, bothJobs.id, bothJobs.matrix)
-                       bothJobs.workflowCallID = workflowParent
+               retval = append(retval, newJobs...)
+       }
+       return retval, nil
+}
 
-                       newJobs, err := 
expandReusableWorkflow(reusableWorkflow, validate, options, pc, jobResults, 
bothJobs.matrix, bothJobs)
+func tryFetchReusableWorkflow(bothJobs *bothJobTypes, pc *parseContext) 
([]byte, error) {
+       workflowJob := bothJobs.workflowJob
+
+       jobType, err := workflowJob.Type()
+       if err != nil {
+               return nil, err
+       }
+
+       if jobType == model.JobTypeReusableWorkflowLocal && 
pc.localWorkflowFetcher != nil {
+               contents, err := pc.localWorkflowFetcher(bothJobs.jobParserJob, 
workflowJob.Uses)
+               if err != nil {
+                       if errors.Is(err, ErrUnsupportedReusableWorkflowFetch) {
+                               // Skip workflow expansion.
+                               return nil, nil
+                       }
+                       return nil, fmt.Errorf("unable to read local workflow 
%q: %w", workflowJob.Uses, err)
+               }
+               return contents, nil
+       } else if jobType == model.JobTypeReusableWorkflowRemote {
+               parsed, err := 
model.ParseRemoteReusableWorkflow(workflowJob.Uses)
+               if err != nil {
+                       return nil, fmt.Errorf("unable to parse `uses: %q` as a 
valid reusable workflow: %w", workflowJob.Uses, err)
+               }
+               external, isExternal := 
parsed.(*model.ExternalReusableWorkflowReference)
+               if !isExternal && pc.instanceWorkflowFetcher != nil {
+                       contents, err := 
pc.instanceWorkflowFetcher(bothJobs.jobParserJob, parsed.Reference())
                        if err != nil {
-                               errors.As(err, &withInvalidJobReference)
-                               errors.As(err, &withInvalidMatrixReference)
-                               if withInvalidJobReference == nil && 
withInvalidMatrixReference == nil {
-                                       return nil, fmt.Errorf("error expanding 
reusable workflow %q: %v", workflowJob.Uses, err)
+                               if errors.Is(err, 
ErrUnsupportedReusableWorkflowFetch) {
+                                       // Skip workflow expansion.
+                                       return nil, nil
                                }
+                               return nil, fmt.Errorf("unable to read instance 
workflow %q: %w", workflowJob.Uses, err)
                        }
-
-                       if withInvalidJobReference == nil && 
withInvalidMatrixReference == nil {
-                               // Append the inner jobs' IDs to the `needs` of 
the parent job.
-                               additionalNeeds := make([]string, len(newJobs))
-                               for i, b := range newJobs {
-                                       additionalNeeds[i] = b.id
+                       return contents, nil
+               } else if isExternal && pc.externalWorkflowFetcher != nil {
+                       contents, err := 
pc.externalWorkflowFetcher(bothJobs.jobParserJob, external)
+                       if err != nil {
+                               if errors.Is(err, 
ErrUnsupportedReusableWorkflowFetch) {
+                                       // Skip workflow expansion.
+                                       return nil, nil
                                }
-                               callerNeeds := bothJobs.jobParserJob.Needs()
-                               callerNeeds = append(callerNeeds, 
additionalNeeds...)
-                               _ = 
bothJobs.jobParserJob.RawNeeds.Encode(callerNeeds)
-
-                               // The calling job will still exist in order to 
act as a `sentinel` for `needs` job ordering & output
-                               // access. We'll take away the job's content to 
ensure nothing is actually executed.
-                               _ = bothJobs.jobParserJob.If.Encode(false)
-                               bothJobs.jobParserJob.Uses = ""
-                               bothJobs.jobParserJob.With = nil
-                       } else {
-                               // Retain all the original data of the job 
until it's really expanded, with its inputs, later
-                               bothJobs.withInvalidJobReference = 
withInvalidJobReference
-                               bothJobs.withInvalidMatrixReference = 
withInvalidMatrixReference
+                               return nil, fmt.Errorf("unable to read external 
workflow %q: %w", workflowJob.Uses, err)
                        }
-
-                       retval = append(retval, newJobs...)
+                       return contents, nil
                }
+
+               // Fallthrough intentional -- `isExternal` and the relevant 
available fetcher didn't combine to have a relevant
+               // fetcher for the type of this reusable workflow.
        }
-       return retval, nil
+
+       // Either not a reusable workflow, or not a reusable workflow type that 
we have a fetcher for.
+       return nil, nil
 }
 
 func expandReusableWorkflow(contents []byte, validate bool, options 
[]ParseOption, pc *parseContext, jobResults map[string]*JobResult, matrix 
map[string]any, callerJob *bothJobTypes) ([]*bothJobTypes, error) {
@@ -493,17 +520,25 @@
                        id:               fmt.Sprintf("%s.%s", callerJob.id, 
id),
                        jobParserJob:     job,
                        workflowJob:      workflow.GetJob(id),
-                       overrideOnClause: rebuiltOn,
+                       overrideOnClause: &swf.RawOn,
 
-                       workflowCallParent: callerJob.workflowCallID,
-               }
-               // Maintain existing ID / Parent if populated in a lower-level 
recursive workflow call
-               if swf.Metadata.WorkflowCallID != "" {
-                       newEntry.workflowCallID = swf.Metadata.WorkflowCallID
-               }
-               if swf.Metadata.WorkflowCallParent != "" {
-                       newEntry.workflowCallParent = 
swf.Metadata.WorkflowCallParent
+                       // Preserve metadata:
+                       workflowCallParent: swf.Metadata.WorkflowCallParent,
+                       workflowCallInputs: swf.Metadata.WorkflowCallInputs,
+                       workflowCallID:     swf.Metadata.WorkflowCallID,
+               }
+
+               // If the new job doesn't have a parent, that means it's a 
direct-child of the job that we're currently
+               // expanding `callerJob`:
+               if newEntry.workflowCallParent == "" {
+                       // Store it's relationship to its parent.
+                       newEntry.workflowCallParent = callerJob.workflowCallID
+
+                       // Store the inputs that were calculated for 
`callerJob` in the `on` clause so that they're used when the
+                       // child job is executed:
+                       newEntry.overrideOnClause = rebuiltOn
                }
+
                if swf.IncompleteMatrix || swf.IncompleteRunsOn || 
swf.IncompleteWith {
                        newEntry.internalIncompleteState = swf
                        // if we have a reference to a job stored in the 
incomplete state, then qualify that job name:
@@ -716,7 +751,7 @@
 // ./.forgejo/workflows/reusable.yml`) into one-or-more jobs contained within 
the local workflow.  The
 // `localWorkflowFetcher` function allows jobparser to read the target 
workflow file.
 //
-// The `localWorkflowFetcher` can return the error 
ErrUnsupportedReusableWorkflowFetch if the fetcher doesn't support
+// The `localWorkflowFetcher` can return the error 
[ErrUnsupportedReusableWorkflowFetch] if the fetcher doesn't support
 // the target workflow for job parsing.  The job will go to the "fallback" 
mode of operation where its internal jobs are
 // not expanded into the parsed workflow, and it can still be executed as a 
single monolithic job.  All other errors are
 // considered fatal for job parsing.
@@ -726,20 +761,31 @@
        }
 }
 
-// Allows the job parser to convert a workflow job that references a remote 
(eg. not part of the current workflow's
-// repository) reusable workflow (eg. `uses: 
some-org/some-repo/.forgejo/workflows/reusable.yml`) into one-or-more jobs
-// contained within the remote workflow.  The `remoteWorkflowFetcher` function 
allows jobparser to read the target
-// workflow file.
+// Allows the job parser to read a workflow job that references a reusable 
workflow on the same Forgejo instance, but
+// not in the same repository (eg. `uses: 
some-org/some-repo/.forgejo/workflows/reusable.yml`). The workflow is
+// converted into one-or-more jobs contained within the workflow.
 //
-// `ref.Host` will be `nil` if the remote reference was not a fully-qualified 
URL.  No default value is provided.
+// The `instanceWorkflowFetcher` can return the error 
[ErrUnsupportedReusableWorkflowFetch] if the fetcher doesn't
+// support the target workflow for job parsing.  The job will go to the 
"fallback" mode of operation where its internal
+// jobs are not expanded into the parsed workflow, and it can still be 
executed as a single monolithic job.  All other
+// errors are considered fatal for job parsing.
+func ExpandInstanceReusableWorkflows(instanceWorkflowFetcher 
InstanceWorkflowFetcher) ParseOption {
+       return func(c *parseContext) {
+               c.instanceWorkflowFetcher = instanceWorkflowFetcher
+       }
+}
+
+// Allows the job parser to read a workflow job that references an external 
reusable workflow with a fully-qualified URL
+// (eg. `uses: 
https://example.com/some-org/some-repo/.forgejo/workflows/reusable.yml`). The 
workflow is converted into
+// one-or-more jobs contained within the external workflow file.
 //
-// The `remoteWorkflowFetcher` can return the error 
ErrUnsupportedReusableWorkflowFetch if the fetcher doesn't support
-// the target workflow for job parsing.  The job will go to the "fallback" 
mode of operation where its internal jobs are
-// not expanded into the parsed workflow, and it can still be executed as a 
single monolithic job.  All other errors are
-// considered fatal for job parsing.
-func ExpandRemoteReusableWorkflows(remoteWorkflowFetcher 
RemoteWorkflowFetcher) ParseOption {
+// The `externalWorkflowFetcher` can return the error 
[ErrUnsupportedReusableWorkflowFetch] if the fetcher doesn't
+// support the target workflow for job parsing.  The job will go to the 
"fallback" mode of operation where its internal
+// jobs are not expanded into the parsed workflow, and it can still be 
executed as a single monolithic job.  All other
+// errors are considered fatal for job parsing.
+func ExpandExternalReusableWorkflows(externalWorkflowFetcher 
ExternalWorkflowFetcher) ParseOption {
        return func(c *parseContext) {
-               c.remoteWorkflowFetcher = remoteWorkflowFetcher
+               c.externalWorkflowFetcher = externalWorkflowFetcher
        }
 }
 
@@ -756,8 +802,9 @@
 }
 
 type (
-       LocalWorkflowFetcher  func(job *Job, path string) ([]byte, error)
-       RemoteWorkflowFetcher func(job *Job, ref 
*model.RemoteReusableWorkflowWithBaseURL) ([]byte, error)
+       LocalWorkflowFetcher    func(job *Job, path string) ([]byte, error)
+       InstanceWorkflowFetcher func(job *Job, ref 
*model.NonLocalReusableWorkflowReference) ([]byte, error)
+       ExternalWorkflowFetcher func(job *Job, ref 
*model.ExternalReusableWorkflowReference) ([]byte, error)
 )
 
 type parseContext struct {
@@ -769,7 +816,8 @@
        workflowNeeds           []string
        supportIncompleteRunsOn bool
        localWorkflowFetcher    LocalWorkflowFetcher
-       remoteWorkflowFetcher   RemoteWorkflowFetcher
+       instanceWorkflowFetcher InstanceWorkflowFetcher
+       externalWorkflowFetcher ExternalWorkflowFetcher
        recursionDepth          int
        parentUniqueID          string
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/forgejo-runner-12.3.0/act/jobparser/jobparser_test.go 
new/forgejo-runner-12.3.1/act/jobparser/jobparser_test.go
--- old/forgejo-runner-12.3.0/act/jobparser/jobparser_test.go   2025-12-21 
17:32:28.000000000 +0100
+++ new/forgejo-runner-12.3.1/act/jobparser/jobparser_test.go   2025-12-24 
17:06:29.000000000 +0100
@@ -173,7 +173,7 @@
                        name:                           
"expand_remote_workflow",
                        expectingInvalidWorkflowOutput: true,
                        options: []ParseOption{
-                               ExpandRemoteReusableWorkflows(func(job *Job, 
ref *model.RemoteReusableWorkflowWithBaseURL) ([]byte, error) {
+                               ExpandInstanceReusableWorkflows(func(job *Job, 
ref *model.NonLocalReusableWorkflowReference) ([]byte, error) {
                                        if ref.Org != "some-org" {
                                                return nil, 
fmt.Errorf("unexpected remote Org: %q", ref.Org)
                                        }
@@ -183,19 +183,9 @@
                                        if ref.GitPlatform != "forgejo" {
                                                return nil, 
fmt.Errorf("unexpected remote GitPlatform: %q", ref.GitPlatform)
                                        }
-                                       if ref.BaseURL == nil {
-                                               // relative reference in 
expand_remote_workflow.in.yaml
-                                               if ref.Filename != 
"expand_remote_workflow_reusable-2.yml" {
-                                                       return nil, 
fmt.Errorf("unexpected remote Filename: %q", ref.Filename)
-                                               }
-                                       } else {
-                                               // absolute reference in 
expand_remote_workflow.in.yaml
-                                               if *ref.BaseURL != 
"https://example.com"; {
-                                                       return nil, 
fmt.Errorf("unexpected remote Host: %v", ref.BaseURL)
-                                               }
-                                               if ref.Filename != 
"expand_remote_workflow_reusable-1.yml" {
-                                                       return nil, 
fmt.Errorf("unexpected remote Filename: %q", ref.Filename)
-                                               }
+                                       // remote reference in 
expand_remote_workflow.in.yaml
+                                       if ref.Filename != 
"expand_remote_workflow_reusable-2.yml" {
+                                               return nil, 
fmt.Errorf("unexpected remote Filename: %q", ref.Filename)
                                        }
                                        if ref.Ref != "v1" {
                                                return nil, 
fmt.Errorf("unexpected remote Ref: %q", ref.Ref)
@@ -203,6 +193,32 @@
                                        content := ReadTestdata(t, 
"expand_remote_workflow_reusable-1.yaml", true)
                                        return content, nil
                                }),
+                               ExpandExternalReusableWorkflows(func(job *Job, 
ref *model.ExternalReusableWorkflowReference) ([]byte, error) {
+                                       if ref.Org != "some-org" {
+                                               return nil, 
fmt.Errorf("unexpected external Org: %q", ref.Org)
+                                       }
+                                       if ref.Repo != "some-repo" {
+                                               return nil, 
fmt.Errorf("unexpected external Repo: %q", ref.Repo)
+                                       }
+                                       if ref.GitPlatform != "forgejo" {
+                                               return nil, 
fmt.Errorf("unexpected external GitPlatform: %q", ref.GitPlatform)
+                                       }
+                                       // external reference in 
expand_remote_workflow.in.yaml
+                                       if ref.Filename != 
"expand_remote_workflow_reusable-1.yml" {
+                                               return nil, 
fmt.Errorf("unexpected external Filename: %q", ref.Filename)
+                                       }
+                                       if ref.BaseURL != "https://example.com"; 
{
+                                               return nil, 
fmt.Errorf("unexpected external Host: %v", ref.BaseURL)
+                                       }
+                                       if ref.Filename != 
"expand_remote_workflow_reusable-1.yml" {
+                                               return nil, 
fmt.Errorf("unexpected external Filename: %q", ref.Filename)
+                                       }
+                                       if ref.Ref != "v1" {
+                                               return nil, 
fmt.Errorf("unexpected external Ref: %q", ref.Ref)
+                                       }
+                                       content := ReadTestdata(t, 
"expand_remote_workflow_reusable-1.yaml", true)
+                                       return content, nil
+                               }),
                        },
                },
                {
@@ -604,7 +620,7 @@
                swf, err := Parse(
                        []byte(testWorkflow),
                        false,
-                       ExpandRemoteReusableWorkflows(func(job *Job, ref 
*model.RemoteReusableWorkflowWithBaseURL) ([]byte, error) {
+                       ExpandInstanceReusableWorkflows(func(job *Job, ref 
*model.NonLocalReusableWorkflowReference) ([]byte, error) {
                                return []byte(testWorkflow), nil
                        }),
                )
@@ -643,7 +659,7 @@
                        []byte(outerWorkflow),
                        false,
                        WithJobOutputs(jobOutputs),
-                       ExpandRemoteReusableWorkflows(func(job *Job, ref 
*model.RemoteReusableWorkflowWithBaseURL) ([]byte, error) {
+                       ExpandInstanceReusableWorkflows(func(job *Job, ref 
*model.NonLocalReusableWorkflowReference) ([]byte, error) {
                                return []byte(innerWorkflow), nil
                        }),
                )
@@ -672,7 +688,7 @@
                                },
                        }),
                        WithWorkflowNeeds([]string{"some-other-job"}),
-                       ExpandRemoteReusableWorkflows(func(job *Job, ref 
*model.RemoteReusableWorkflowWithBaseURL) ([]byte, error) {
+                       ExpandInstanceReusableWorkflows(func(job *Job, ref 
*model.NonLocalReusableWorkflowReference) ([]byte, error) {
                                callCount++
                                return []byte(outerWorkflow), nil
                        }),
@@ -683,7 +699,7 @@
 }
 
 func TestReusableWorkflowFetcherArgs(t *testing.T) {
-       t.Run("ExpandRemoteReusableWorkflows", func(t *testing.T) {
+       t.Run("ExpandInstanceReusableWorkflows", func(t *testing.T) {
                testWorkflow := `
 on:
   pull_request:
@@ -700,7 +716,7 @@
                swf, err := Parse(
                        []byte(testWorkflow),
                        false,
-                       ExpandRemoteReusableWorkflows(func(job *Job, ref 
*model.RemoteReusableWorkflowWithBaseURL) ([]byte, error) {
+                       ExpandInstanceReusableWorkflows(func(job *Job, ref 
*model.NonLocalReusableWorkflowReference) ([]byte, error) {
                                executed = true
                                // validate `job` passed in is correct/expected 
object
                                assert.Equal(t, []string{"ubuntu-latest"}, 
job.RunsOn())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive-1.yaml
 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive-1.yaml
--- 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive-1.yaml
     2025-12-21 17:32:28.000000000 +0100
+++ 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive-1.yaml
     2025-12-24 17:06:29.000000000 +0100
@@ -1,3 +1,8 @@
+on:
+  workflow_call:
+    inputs:
+      input1:
+        type: string
 name: test
 jobs:
   job1:
@@ -7,3 +12,6 @@
   reusable-2:
     uses: ./.forgejo/workflows/expand_reusable_needs_recursive-2.yml
     needs: job1
+    with:
+      input1: ${{ inputs.input1 }}
+      input2: this input comes from the first layer inner job
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive-2.yaml
 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive-2.yaml
--- 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive-2.yaml
     2025-12-21 17:32:28.000000000 +0100
+++ 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive-2.yaml
     2025-12-24 17:06:29.000000000 +0100
@@ -1,3 +1,10 @@
+on:
+  workflow_call:
+    inputs:
+      input1:
+        type: string
+      input2:
+        type: string
 name: test
 jobs:
   job1:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive.in.yaml
 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive.in.yaml
--- 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive.in.yaml
    2025-12-21 17:32:28.000000000 +0100
+++ 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive.in.yaml
    2025-12-24 17:06:29.000000000 +0100
@@ -2,3 +2,5 @@
 jobs:
   reusable-1:
     uses: ./.forgejo/workflows/expand_reusable_needs_recursive-1.yml
+    with:
+      input1: this input comes from the outer job
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive.out.yaml
 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive.out.yaml
--- 
old/forgejo-runner-12.3.0/act/jobparser/testdata/expand_reusable_needs_recursive.out.yaml
   2025-12-21 17:32:28.000000000 +0100
+++ 
new/forgejo-runner-12.3.1/act/jobparser/testdata/expand_reusable_needs_recursive.out.yaml
   2025-12-24 17:06:29.000000000 +0100
@@ -9,9 +9,17 @@
     runs-on: []
     if: false
 __metadata:
+  workflow_call_inputs:
+    input1: this input comes from the outer job
   workflow_call_id: 
b5a9f46f1f2513d7777fde50b169d323a6519e349cc175484c947ac315a209ed
 ---
 name: test
+"on":
+  workflow_call:
+    inputs:
+      input1:
+        default: this input comes from the outer job
+        type: string
 jobs:
   reusable-1.job1:
     name: job1
@@ -22,6 +30,12 @@
   workflow_call_parent: 
b5a9f46f1f2513d7777fde50b169d323a6519e349cc175484c947ac315a209ed
 ---
 name: test
+"on":
+  workflow_call:
+    inputs:
+      input1:
+        default: this input comes from the outer job
+        type: string
 jobs:
   reusable-1.reusable-2:
     name: reusable-2
@@ -31,10 +45,22 @@
     runs-on: []
     if: false
 __metadata:
+  workflow_call_inputs:
+    input1: this input comes from the outer job
+    input2: this input comes from the first layer inner job
   workflow_call_id: 
ea7d9f7b51d5cee1511dbe76b9763615f58ecbcb7832e144a8eec2535b380f1e
   workflow_call_parent: 
b5a9f46f1f2513d7777fde50b169d323a6519e349cc175484c947ac315a209ed
 ---
 name: test
+"on":
+  workflow_call:
+    inputs:
+      input1:
+        default: this input comes from the outer job
+        type: string
+      input2:
+        default: this input comes from the first layer inner job
+        type: string
 jobs:
   reusable-1.reusable-2.job1:
     name: job1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/forgejo-runner-12.3.0/act/model/reusable.go 
new/forgejo-runner-12.3.1/act/model/reusable.go
--- old/forgejo-runner-12.3.0/act/model/reusable.go     2025-12-21 
17:32:28.000000000 +0100
+++ new/forgejo-runner-12.3.1/act/model/reusable.go     2025-12-24 
17:06:29.000000000 +0100
@@ -7,9 +7,19 @@
        "strings"
 )
 
-// Parsed version of a remote `job.<job-id>.uses:` reference, such as `uses:
-// org/repo/.forgejo/workflows/reusable-workflow.yml`.
-type RemoteReusableWorkflow struct {
+// NonLocalReusableWorkflow is either a [NonLocalReusableWorkflowReference] or 
an [ExternalReusableWorkflowReference].
+type NonLocalReusableWorkflow interface {
+       // Access the shared details that are present on all non-local reusable 
workflows.
+       Reference() *NonLocalReusableWorkflowReference
+
+       // ConvertExternalWithDefaultBaseURL converts this reference from a 
remote into an external reference with the given
+       // base URL. If it is already an external reference, it is returned 
unchanged.
+       ConvertExternalWithDefaultBaseURL(baseURL string) 
*ExternalReusableWorkflowReference
+}
+
+// Parsed version of a `job.<job-id>.uses:` reference, such as `uses:
+// org/repo/.forgejo/workflows/reusable-workflow.yml@v1`
+type NonLocalReusableWorkflowReference struct {
        Org      string
        Repo     string
        Filename string
@@ -18,9 +28,8 @@
        GitPlatform string
 }
 
-// newRemoteReusableWorkflowWithPlat create a `remoteReusableWorkflow`
-// workflows from `.gitea/workflows` and `.github/workflows` are supported
-func NewRemoteReusableWorkflowWithPlat(uses string) *RemoteReusableWorkflow {
+// parseReusableWorkflowReference parses a workflow reference like 
`.forgejo/workflows/reusable-workflow.yml@v1`
+func parseReusableWorkflowReference(uses string) 
*NonLocalReusableWorkflowReference {
        // GitHub docs:
        // 
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_iduses
        r := 
regexp.MustCompile(`^([^/]+)/([^/]+)/\.([^/]+)/workflows/([^@]+)@(.*)$`)
@@ -28,7 +37,7 @@
        if len(matches) != 6 {
                return nil
        }
-       return &RemoteReusableWorkflow{
+       return &NonLocalReusableWorkflowReference{
                Org:         matches[1],
                Repo:        matches[2],
                GitPlatform: matches[3],
@@ -37,27 +46,45 @@
        }
 }
 
-func (r *RemoteReusableWorkflow) FilePath() string {
+func (r *NonLocalReusableWorkflowReference) FilePath() string {
        return fmt.Sprintf("./.%s/workflows/%s", r.GitPlatform, r.Filename)
 }
 
-type RemoteReusableWorkflowWithBaseURL struct {
-       RemoteReusableWorkflow
-       BaseURL *string
+func (r *NonLocalReusableWorkflowReference) Reference() 
*NonLocalReusableWorkflowReference {
+       return r
 }
 
-func (r *RemoteReusableWorkflowWithBaseURL) CloneURL() string {
-       if r.BaseURL == nil {
-               return ""
+func (r *NonLocalReusableWorkflowReference) 
ConvertExternalWithDefaultBaseURL(defaultBaseURL string) 
*ExternalReusableWorkflowReference {
+       return &ExternalReusableWorkflowReference{
+               NonLocalReusableWorkflowReference: *r,
+               BaseURL:                           defaultBaseURL,
        }
-       return fmt.Sprintf("%s/%s/%s", *r.BaseURL, r.Org, r.Repo)
 }
 
-// Parses a `uses` declaration for a "remote" (not this repo) reusable 
workflow.  Typically something like
-// "some-org/some-repo/.forgejo/workflows/called-workflow.yml@v1".  Can also 
be domain-qualified, in which case the
-// `BaseURL` field will be populated -- otherwise it should be assumed to be 
an org/repo on the same Forgejo instance as
-// the `uses: ...` was declared.
-func ParseRemoteReusableWorkflow(uses string) 
(*RemoteReusableWorkflowWithBaseURL, error) {
+// Parsed version of `job.<job-id>.uses:` which is fully qualified with a URL, 
such as `uses:
+// https://example.com/org/repo/.forgejo/workflows/reusable-workflow.yml@v1`.  
An external workflow reference has a
+// BaseURL that represents the `https://example.com` base.
+type ExternalReusableWorkflowReference struct {
+       NonLocalReusableWorkflowReference
+       BaseURL string
+}
+
+func (r *ExternalReusableWorkflowReference) CloneURL() string {
+       return fmt.Sprintf("%s/%s/%s", r.BaseURL, r.Org, r.Repo)
+}
+
+func (r *ExternalReusableWorkflowReference) Reference() 
*NonLocalReusableWorkflowReference {
+       return &r.NonLocalReusableWorkflowReference
+}
+
+func (r *ExternalReusableWorkflowReference) 
ConvertExternalWithDefaultBaseURL(defaultBaseURL string) 
*ExternalReusableWorkflowReference {
+       return r
+}
+
+// Parses a `uses` declaration such as `uses: 
some-org/some-repo/.forgejo/workflows/called-workflow.yml@v1`.  The
+// returned object may be a [NonLocalReusableWorkflowReference] or an 
[ExternalReusableWorkflowReference] if it was a fully
+// qualified URL.
+func ParseRemoteReusableWorkflow(uses string) (NonLocalReusableWorkflow, 
error) {
        url, err := url.Parse(uses)
        if err != nil {
                return nil, fmt.Errorf("'%s' cannot be parsed as a URL: %v", 
uses, err)
@@ -71,12 +98,16 @@
                baseURL = &innerBaseURL
        }
 
-       remoteReusableWorkflow := 
NewRemoteReusableWorkflowWithPlat(strings.TrimPrefix(url.Path, "/"))
-       if remoteReusableWorkflow == nil {
+       reusableWorkflowReference := 
parseReusableWorkflowReference(strings.TrimPrefix(url.Path, "/"))
+       if reusableWorkflowReference == nil {
                return nil, fmt.Errorf("expected format 
{owner}/{repo}/.{git_platform}/workflows/{filename}@{ref}. Actual '%s' Input 
string was not in a correct format", url.Path)
        }
-       return &RemoteReusableWorkflowWithBaseURL{
-               RemoteReusableWorkflow: *remoteReusableWorkflow,
-               BaseURL:                baseURL,
+       if baseURL == nil {
+               return reusableWorkflowReference, nil
+       }
+
+       return &ExternalReusableWorkflowReference{
+               NonLocalReusableWorkflowReference: *reusableWorkflowReference,
+               BaseURL:                           *baseURL,
        }, nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/forgejo-runner-12.3.0/act/model/reusable_test.go 
new/forgejo-runner-12.3.1/act/model/reusable_test.go
--- old/forgejo-runner-12.3.0/act/model/reusable_test.go        2025-12-21 
17:32:28.000000000 +0100
+++ new/forgejo-runner-12.3.1/act/model/reusable_test.go        2025-12-24 
17:06:29.000000000 +0100
@@ -68,17 +68,18 @@
                        } else {
                                require.NoError(t, err)
                                assert.NotNil(t, result)
+                               external, ok := 
result.(*ExternalReusableWorkflowReference)
                                if tt.expectedBaseURL != "" {
-                                       require.NotNil(t, result.BaseURL)
-                                       assert.Equal(t, tt.expectedBaseURL, 
*result.BaseURL)
+                                       require.True(t, ok)
+                                       assert.Equal(t, tt.expectedBaseURL, 
external.BaseURL)
                                } else {
-                                       assert.Nil(t, result.BaseURL)
+                                       assert.False(t, ok)
                                }
-                               assert.Equal(t, tt.expectedOrg, result.Org)
-                               assert.Equal(t, tt.expectedRepo, result.Repo)
-                               assert.Equal(t, tt.expectedPlatform, 
result.GitPlatform)
-                               assert.Equal(t, tt.expectedFilename, 
result.Filename)
-                               assert.Equal(t, tt.expectedRef, result.Ref)
+                               assert.Equal(t, tt.expectedOrg, 
result.Reference().Org)
+                               assert.Equal(t, tt.expectedRepo, 
result.Reference().Repo)
+                               assert.Equal(t, tt.expectedPlatform, 
result.Reference().GitPlatform)
+                               assert.Equal(t, tt.expectedFilename, 
result.Reference().Filename)
+                               assert.Equal(t, tt.expectedRef, 
result.Reference().Ref)
                        }
                })
        }
@@ -130,7 +131,7 @@
 
        for _, tt := range tests {
                t.Run(tt.name, func(t *testing.T) {
-                       result := NewRemoteReusableWorkflowWithPlat(tt.uses)
+                       result := parseReusableWorkflowReference(tt.uses)
 
                        if tt.shouldFail {
                                assert.Nil(t, result)
@@ -147,13 +148,12 @@
 }
 
 func TestRemoteReusableWorkflow_CloneURL(t *testing.T) {
-       baseURL := "https://code.forgejo.org";
-       rw := &RemoteReusableWorkflowWithBaseURL{
-               RemoteReusableWorkflow: RemoteReusableWorkflow{
+       rw := &ExternalReusableWorkflowReference{
+               NonLocalReusableWorkflowReference: 
NonLocalReusableWorkflowReference{
                        Org:  "owner",
                        Repo: "repo",
                },
-               BaseURL: &baseURL,
+               BaseURL: "https://code.forgejo.org";,
        }
        assert.Equal(t, "https://code.forgejo.org/owner/repo";, rw.CloneURL())
 }
@@ -187,7 +187,7 @@
 
        for _, tt := range tests {
                t.Run(tt.name, func(t *testing.T) {
-                       rw := &RemoteReusableWorkflow{
+                       rw := &NonLocalReusableWorkflowReference{
                                GitPlatform: tt.gitPlatform,
                                Filename:    tt.filename,
                        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/forgejo-runner-12.3.0/act/runner/reusable_workflow.go 
new/forgejo-runner-12.3.1/act/runner/reusable_workflow.go
--- old/forgejo-runner-12.3.0/act/runner/reusable_workflow.go   2025-12-21 
17:32:28.000000000 +0100
+++ new/forgejo-runner-12.3.1/act/runner/reusable_workflow.go   2025-12-24 
17:06:29.000000000 +0100
@@ -41,18 +41,21 @@
        if err != nil {
                return common.NewErrorExecutor(err)
        }
-       if reusable.BaseURL == nil {
-               reusable.BaseURL = getBaseURL(rc.Config.GitHubInstance)
+       var externalReference *model.ExternalReusableWorkflowReference
+       baseURL := getBaseURL(rc.Config.GitHubInstance)
+       if baseURL == nil {
+               return common.NewErrorExecutor(fmt.Errorf("unable to determine 
base URL for reusable workflow reference, configured base is %q", 
rc.Config.GitHubInstance))
        }
+       externalReference = reusable.ConvertExternalWithDefaultBaseURL(*baseURL)
 
        // If the repository is private, we need a token to clone it
        token := rc.Config.GetToken()
 
        makeWorkflowExecutorForWorkTree := func(workflowDir string) 
common.Executor {
-               return newReusableWorkflowExecutor(rc, workflowDir, 
reusable.FilePath())
+               return newReusableWorkflowExecutor(rc, workflowDir, 
reusable.Reference().FilePath())
        }
 
-       return cloneIfRequired(rc, reusable, token, 
makeWorkflowExecutorForWorkTree)
+       return cloneIfRequired(rc, externalReference, token, 
makeWorkflowExecutorForWorkTree)
 }
 
 // See "Obsolete" note on newLocalReusableWorkflowExecutor -- applies to this 
as well.
@@ -63,18 +66,28 @@
        if err != nil {
                return common.NewErrorExecutor(err)
        }
-       if reusable.BaseURL == nil {
-               reusable.BaseURL = getBaseURL(rc.Config.GitHubInstance)
+       var externalReference *model.ExternalReusableWorkflowReference
+       baseURL := getBaseURL(rc.Config.GitHubInstance)
+       if baseURL == nil {
+               // reusable can be in two states, it can either be a external 
reference already in which case we don't need
+               // `baseURL`, or it can be a reference where we do need baseURL.
+               f, isExternal := 
reusable.(*model.ExternalReusableWorkflowReference)
+               if !isExternal {
+                       return common.NewErrorExecutor(fmt.Errorf("unable to 
determine base URL for reusable workflow reference %q, configured base is %q", 
uses, rc.Config.GitHubInstance))
+               }
+               externalReference = f
+       } else {
+               externalReference = 
reusable.ConvertExternalWithDefaultBaseURL(*baseURL)
        }
 
        // FIXME: if the reusable workflow is from a private repository, we 
need to provide a token to access the repository.
        token := ""
 
        makeWorkflowExecutorForWorkTree := func(workflowDir string) 
common.Executor {
-               return newReusableWorkflowExecutor(rc, workflowDir, 
reusable.FilePath())
+               return newReusableWorkflowExecutor(rc, workflowDir, 
reusable.Reference().FilePath())
        }
 
-       return cloneIfRequired(rc, reusable, token, 
makeWorkflowExecutorForWorkTree)
+       return cloneIfRequired(rc, externalReference, token, 
makeWorkflowExecutorForWorkTree)
 }
 
 // gitHubInstance can be a URL or just a hostname -- return a URL for 
consistency
@@ -89,7 +102,7 @@
        return nil
 }
 
-func cloneIfRequired(rc *RunContext, remoteReusableWorkflow 
*model.RemoteReusableWorkflowWithBaseURL, token string, 
makeWorkflowExecutorForWorkTree func(workflowDir string) common.Executor) 
common.Executor {
+func cloneIfRequired(rc *RunContext, remoteReusableWorkflow 
*model.ExternalReusableWorkflowReference, token string, 
makeWorkflowExecutorForWorkTree func(workflowDir string) common.Executor) 
common.Executor {
        return func(ctx context.Context) error {
                // Do not change the remoteReusableWorkflow.URL, because:
                //      1. Gitea doesn't support specifying 
GithubContext.ServerURL by the GITHUB_SERVER_URL env

++++++ forgejo-runner.obsinfo ++++++
--- /var/tmp/diff_new_pack.QnEcko/_old  2025-12-25 19:58:04.272280160 +0100
+++ /var/tmp/diff_new_pack.QnEcko/_new  2025-12-25 19:58:04.284280648 +0100
@@ -1,5 +1,5 @@
 name: forgejo-runner
-version: 12.3.0
-mtime: 1766334748
-commit: 54bfaa785975eae868b6e5918d727f30c6d90445
+version: 12.3.1
+mtime: 1766592389
+commit: 4e1da369ef8c5e6ce963b0121393af6f78d0df0b
 

++++++ vendor.tar.gz ++++++

Reply via email to