Files
upstream-gitea/modules/actions/jobparser/roundtrip_test.go
upstream-mirror 52ae0c5802
Some checks failed
cache-seeder / prune (push) Has been skipped
cache-seeder / frontend (push) Failing after 3s
cache-seeder / python (push) Failing after 3s
cache-seeder / gobuild (push) Failing after 4s
cache-seeder / lint (bindata, lint-backend) (push) Failing after 3s
giteabot backport / giteabot (push) Has been skipped
giteabot / giteabot (push) Has been skipped
cache-prune / prune (push) Has been skipped
release-nightly-snapcraft / build-and-publish (ubuntu-24.04) (push) Has been cancelled
release-nightly-snapcraft / build-and-publish (ubuntu-24.04-arm) (push) Has been cancelled
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
cron-renovate / cron-renovate (push) Has been skipped
snapshot of https://github.com/go-gitea/gitea.git (main, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:41:59 +05:00

107 lines
3.1 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package jobparser
import (
"bytes"
"testing"
"gitea.dev/actionslib/pkg/model"
"github.com/stretchr/testify/require"
)
// A step whose `run:` block starts with blank lines must still survive the
// Parse -> SingleWorkflow.Marshal -> Parse round-trip. Previously Marshal used a
// different indentation than SetJob, which made the encoder emit the block scalar
// with a wrong explicit indentation indicator (`run: |4`) that no longer parsed;
// the job then stayed silently blocked during concurrency evaluation.
func TestSingleWorkflowRoundTripRunBlockLeadingBlankLines(t *testing.T) {
const wf = `name: demo
on:
workflow_call:
inputs:
app_name:
type: string
required: true
jobs:
build:
name: build
env:
IMAGE_TAG: ${{ inputs.app_name }}
runs-on: ubuntu-latest
steps:
- if: ${{ inputs.app_name != '' }}
name: packages
run: |
echo start
echo done
`
sws, err := Parse([]byte(wf))
require.NoError(t, err)
require.Len(t, sws, 1)
// pin the original run block as the baseline
_, origJob := sws[0].Job()
require.Len(t, origJob.Steps, 1)
const wantRun = "\n\necho start\necho done\n"
require.Equal(t, wantRun, string(origJob.Steps[0].Run))
payload, err := sws[0].Marshal()
require.NoError(t, err)
// the serialized single workflow must be parseable again -- this is what the
// server does in EvaluateJobConcurrencyFillModel -> ParseJob. Before the fix
// Marshal emitted `run: |4`, which failed here and left the job blocked.
roundTripped, err := Parse(payload)
require.NoError(t, err, "serialized single workflow must round-trip; got payload:\n%s", payload)
require.Len(t, roundTripped, 1)
// the round-trip must preserve the run block byte-for-byte
_, gotJob := roundTripped[0].Job()
require.Len(t, gotJob.Steps, 1)
require.Equal(t, wantRun, string(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)
}
}