mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-08 14:03:24 +09:00
fix(actions): keep step-level continue-on-error expressions unevaluated (#39141)
Signed-off-by: silverwind <me@silverwind.io> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/actionslib/pkg/expreval"
|
"gitea.dev/actionslib/pkg/expreval"
|
||||||
"gitea.dev/actionslib/pkg/exprparser"
|
"gitea.dev/actionslib/pkg/exprparser"
|
||||||
@@ -175,17 +176,29 @@ func (j *Job) RunsOn() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Step struct {
|
type Step struct {
|
||||||
ID string `yaml:"id,omitempty"`
|
ID string `yaml:"id,omitempty"`
|
||||||
If yaml.Node `yaml:"if,omitempty"`
|
If yaml.Node `yaml:"if,omitempty"`
|
||||||
Name string `yaml:"name,omitempty"`
|
Name string `yaml:"name,omitempty"`
|
||||||
Uses string `yaml:"uses,omitempty"`
|
Uses string `yaml:"uses,omitempty"`
|
||||||
Run string `yaml:"run,omitempty"`
|
Run string `yaml:"run,omitempty"`
|
||||||
WorkingDirectory string `yaml:"working-directory,omitempty"`
|
WorkingDirectory string `yaml:"working-directory,omitempty"`
|
||||||
Shell string `yaml:"shell,omitempty"`
|
Shell string `yaml:"shell,omitempty"`
|
||||||
Env yaml.Node `yaml:"env,omitempty"`
|
Env yaml.Node `yaml:"env,omitempty"`
|
||||||
With map[string]string `yaml:"with,omitempty"`
|
With map[string]string `yaml:"with,omitempty"`
|
||||||
ContinueOnError bool `yaml:"continue-on-error,omitempty"`
|
RawContinueOnError yaml.Node `yaml:"continue-on-error,omitempty"` // raw: the runner evaluates it with the steps context
|
||||||
TimeoutMinutes string `yaml:"timeout-minutes,omitempty"`
|
TimeoutMinutes string `yaml:"timeout-minutes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML canonicalizes booleans like continue-on-error
|
||||||
|
func (s *Step) UnmarshalYAML(node *yaml.Node) error {
|
||||||
|
type rawStep Step
|
||||||
|
if err := node.Decode((*rawStep)(s)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if raw := &s.RawContinueOnError; raw.Tag == "!!bool" {
|
||||||
|
raw.Value = strings.ToLower(raw.Value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// String gets the name of step
|
// String gets the name of step
|
||||||
|
|||||||
@@ -4,8 +4,11 @@
|
|||||||
package jobparser
|
package jobparser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dev/actionslib/pkg/model"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,3 +65,42 @@ jobs:
|
|||||||
require.Len(t, gotJob.Steps, 1)
|
require.Len(t, gotJob.Steps, 1)
|
||||||
require.Equal(t, wantRun, gotJob.Steps[0].Run, "round-trip must preserve run content; got payload:\n%s", payload)
|
require.Equal(t, wantRun, gotJob.Steps[0].Run, "round-trip must preserve run content; got payload:\n%s", payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Typing a step's continue-on-error as a bool used to reject the whole `jobs:` node.
|
||||||
|
func TestSingleWorkflowRoundTripStepContinueOnError(t *testing.T) {
|
||||||
|
const wf = `name: demo
|
||||||
|
on: push
|
||||||
|
jobs:
|
||||||
|
job1:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- id: quarantine
|
||||||
|
run: echo "q=true" >> "$GITHUB_OUTPUT"
|
||||||
|
- run: exit 1
|
||||||
|
continue-on-error: ${{ steps.quarantine.outputs.q == 'true' }}
|
||||||
|
- run: exit 1
|
||||||
|
continue-on-error: true
|
||||||
|
- run: exit 1
|
||||||
|
continue-on-error: TRUE
|
||||||
|
- run: exit 1
|
||||||
|
continue-on-error: false
|
||||||
|
- run: exit 1
|
||||||
|
continue-on-error: yes
|
||||||
|
`
|
||||||
|
want := []string{"", "${{ steps.quarantine.outputs.q == 'true' }}", "true", "true", "false", "yes"}
|
||||||
|
|
||||||
|
sws, err := Parse([]byte(wf))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, sws, 1)
|
||||||
|
|
||||||
|
payload, err := sws[0].Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
rw, err := model.ReadWorkflow(bytes.NewReader(payload))
|
||||||
|
require.NoError(t, err, "payload:\n%s", payload)
|
||||||
|
steps := rw.Jobs["job1"].Steps
|
||||||
|
require.Len(t, steps, len(want))
|
||||||
|
for i, w := range want {
|
||||||
|
require.Equal(t, w, steps[i].RawContinueOnError, "step %d, payload:\n%s", i, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user