3.5 KiB · text History b868907
defmodule GitGud.Workflows.SkipCiTest do
  @moduledoc """
  `[skip ci]` and friends: a `push` or `pull_request` whose head commit
  asks for no CI creates no runs; other events don't look.
  """
  use GitGud.DataCase, async: false
  use Oban.Testing, repo: GitGud.Repo

  alias GitGud.PullRequests
  alias GitGud.Repositories.Repository
  alias GitGud.Workflows
  alias GitGud.Workflows.WorkflowRun

  import GitGud.ForgeFixtures
  import GitGud.WorkflowGitHelpers

  doctest GitGud.Workflows, only: [skip_ci?: 1]

  @wf ".forgejo/workflows/ci.yml"

  @workflow """
  name: ci
  on:
    push:
    pull_request:
    workflow_dispatch:
  jobs:
    build:
      runs-on: self-hosted
      steps:
        - run: echo hello
  """

  setup do
    {user, repo} = repository_fixture()
    {:ok, repo: repo, user: user}
  end

  defp runs(%Repository{id: rid}, trigger) do
    from(r in WorkflowRun, where: r.repository_id == ^rid and r.trigger == ^trigger)
    |> Repo.all()
  end

  describe "skip_ci?/1" do
    test "each marker, in any case" do
      for marker <- ["[skip ci]", "[ci skip]", "[no ci]", "[skip actions]", "[actions skip]"] do
        assert Workflows.skip_ci?("Fix it " <> marker)
        assert Workflows.skip_ci?(String.upcase(marker) <> " fix it")
      end
    end

    test "the skip-checks trailer, with or without the space" do
      assert Workflows.skip_ci?("Fix it\n\nskip-checks: true")
      assert Workflows.skip_ci?("Fix it\n\nSigned-off-by: a <a@b>\nskip-checks:true\n")
      refute Workflows.skip_ci?("Fix it\n\nskip-checks: false")
      refute Workflows.skip_ci?("mentions skip-checks: true inline")
    end

    test "an ordinary message, or none" do
      refute Workflows.skip_ci?("skip the ci step")
      refute Workflows.skip_ci?("[skip-ci]")
      refute Workflows.skip_ci?(nil)
    end
  end

  describe "push" do
    test "a head commit saying [skip ci] runs nothing", %{repo: repo, user: user} do
      head = commit!(repo, %{@wf => @workflow}, [], "Docs only [skip ci]")
      push_ref!(repo, "refs/heads/main", nil, head, user.id)

      assert runs(repo, "push") == []
    end

    test "a marker in an earlier commit of the push doesn't skip", %{repo: repo, user: user} do
      first = commit!(repo, %{@wf => @workflow}, [], "wip [skip ci]")
      head = commit!(repo, %{@wf => @workflow, "a" => "a\n"}, [first], "done")
      push_ref!(repo, "refs/heads/main", nil, head, user.id)

      assert [_run] = runs(repo, "push")
    end

    test "the trailer skips too", %{repo: repo, user: user} do
      head = commit!(repo, %{@wf => @workflow}, [], "Tidy\n\nskip-checks: true")
      push_ref!(repo, "refs/heads/main", nil, head, user.id)

      assert runs(repo, "push") == []
    end
  end

  test "a pull request whose head says [skip ci] runs nothing", %{repo: repo, user: user} do
    main = commit!(repo, %{@wf => @workflow}, [])
    git!(repo.disk_path, ["update-ref", "refs/heads/main", main])
    feature = commit!(repo, %{@wf => @workflow, "a" => "a\n"}, [main], "WIP [CI SKIP]")
    git!(repo.disk_path, ["update-ref", "refs/heads/feature", feature])

    {:ok, _pr} = PullRequests.create_pull_request(repo, user, pr_attrs("feature", "main"))
    Oban.drain_queue(queue: :ci)

    assert runs(repo, "pull_request") == []
  end

  test "workflow_dispatch is not skipped", %{repo: repo} do
    head = commit!(repo, %{@wf => @workflow}, [], "Release [skip ci]")
    git!(repo.disk_path, ["update-ref", "refs/heads/main", head])

    assert {:ok, %WorkflowRun{trigger: "workflow_dispatch"}} =
             Workflows.dispatch_manual(repo, "ci.yml", "main")
  end
end