Unverified Commit 95db6c67 authored by Adam C. Stephens's avatar Adam C. Stephens Committed by GitHub
Browse files

Merge pull request #303149 from emilylange/forgejo-test-forgejo-actions

nixos/tests/forgejo: refactor and test Forgejo Actions workflow, nixos/gitea-actions-runner: set the `$HOME` environment variable
parents c9610778 1ec3a5a4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -203,6 +203,8 @@ in
            TOKEN = "${instance.token}";
          } // optionalAttrs (wantsPodman) {
            DOCKER_HOST = "unix:///run/podman/podman.sock";
          } // {
            HOME = "/var/lib/gitea-runner/${name}";
          };
          path = with pkgs; [
            coreutils
+115 −41
Original line number Diff line number Diff line
@@ -22,8 +22,27 @@ let
  '';
  signingPrivateKeyId = "4D642DE8B678C79D";

  actionsWorkflowYaml = ''
    run-name: dummy workflow
    on:
      push:
    jobs:
      cat:
        runs-on: native
        steps:
          - uses: http://localhost:3000/test/checkout@main
          - run: cat testfile
  '';
  # https://github.com/actions/checkout/releases
  checkoutActionSource = pkgs.fetchFromGitHub {
    owner = "actions";
    repo = "checkout";
    rev = "v4.1.1";
    hash = "sha256-h2/UIp8IjPo3eE4Gzx52Fb7pcgG/Ww7u31w5fdKVMos=";
  };

  supportedDbTypes = [ "mysql" "postgres" "sqlite3" ];
  makeGForgejoTest = type: nameValuePair type (makeTest {
  makeForgejoTest = type: nameValuePair type (makeTest {
    name = "forgejo-${type}";
    meta.maintainers = with maintainers; [ bendlas emilylange ];

@@ -36,23 +55,30 @@ let
          settings.service.DISABLE_REGISTRATION = true;
          settings."repository.signing".SIGNING_KEY = signingPrivateKeyId;
          settings.actions.ENABLED = true;
          settings.repository = {
            ENABLE_PUSH_CREATE_USER = true;
            DEFAULT_PUSH_CREATE_PRIVATE = false;
          };
        environment.systemPackages = [ config.services.forgejo.package pkgs.gnupg pkgs.jq pkgs.file ];
        };
        environment.systemPackages = [ config.services.forgejo.package pkgs.gnupg pkgs.jq pkgs.file pkgs.htmlq ];
        services.openssh.enable = true;

        specialisation.runner = {
          inheritParentConfig = true;
          configuration.services.gitea-actions-runner.instances."test" = {
          configuration.services.gitea-actions-runner = {
            package = pkgs.forgejo-runner;
            instances."test" = {
              enable = true;
              name = "ci";
              url = "http://localhost:3000";
              labels = [
              # don't require docker/podman
                # type ":host" does not depend on docker/podman/lxc
                "native:host"
              ];
              tokenFile = "/var/lib/forgejo/runner_token";
            };
          };
        };
        specialisation.dump = {
          inheritParentConfig = true;
          configuration.services.forgejo.dump = {
@@ -62,11 +88,20 @@ let
          };
        };
      };
      client1 = { config, pkgs, ... }: {
        environment.systemPackages = [ pkgs.git ];
      client = { ... }: {
        programs.git = {
          enable = true;
          config = {
            user.email = "test@localhost";
            user.name = "test";
            init.defaultBranch = "main";
          };
        };
      client2 = { config, pkgs, ... }: {
        environment.systemPackages = [ pkgs.git ];
        programs.ssh.extraConfig = ''
          Host *
            StrictHostKeyChecking no
            IdentityFile ~/.ssh/privk
        '';
      };
    };

@@ -75,26 +110,23 @@ let
        inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
        serverSystem = nodes.server.system.build.toplevel;
        dumpFile = with nodes.server.specialisation.dump.configuration.services.forgejo.dump; "${backupDir}/${file}";
        remoteUri = "forgejo@server:test/repo";
        remoteUriCheckoutAction = "forgejo@server:test/checkout";
      in
      ''
        import json
        GIT_SSH_COMMAND = "ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no"
        REPO = "forgejo@server:test/repo"
        PRIVK = "${snakeOilPrivateKey}"

        start_all()

        client1.succeed("mkdir /tmp/repo")
        client1.succeed("mkdir -p $HOME/.ssh")
        client1.succeed(f"cat {PRIVK} > $HOME/.ssh/privk")
        client1.succeed("chmod 0400 $HOME/.ssh/privk")
        client1.succeed("git -C /tmp/repo init")
        client1.succeed("echo hello world > /tmp/repo/testfile")
        client1.succeed("git -C /tmp/repo add .")
        client1.succeed("git config --global user.email test@localhost")
        client1.succeed("git config --global user.name test")
        client1.succeed("git -C /tmp/repo commit -m 'Initial import'")
        client1.succeed(f"git -C /tmp/repo remote add origin {REPO}")
        client.succeed("mkdir -p ~/.ssh")
        client.succeed("(umask 0077; cat ${snakeOilPrivateKey} > ~/.ssh/privk)")

        client.succeed("mkdir /tmp/repo")
        client.succeed("git -C /tmp/repo init")
        client.succeed("echo 'hello world' > /tmp/repo/testfile")
        client.succeed("git -C /tmp/repo add .")
        client.succeed("git -C /tmp/repo commit -m 'Initial import'")
        client.succeed("git -C /tmp/repo remote add origin ${remoteUri}")

        server.wait_for_unit("forgejo.service")
        server.wait_for_open_port(3000)
@@ -143,18 +175,14 @@ let
            + ' -d \'{"key":"${snakeOilPublicKey}","read_only":true,"title":"SSH"}\'''
        )

        client1.succeed(
            f"GIT_SSH_COMMAND='{GIT_SSH_COMMAND}' git -C /tmp/repo push origin master"
        )
        client.succeed("git -C /tmp/repo push origin main")

        client2.succeed("mkdir -p $HOME/.ssh")
        client2.succeed(f"cat {PRIVK} > $HOME/.ssh/privk")
        client2.succeed("chmod 0400 $HOME/.ssh/privk")
        client2.succeed(f"GIT_SSH_COMMAND='{GIT_SSH_COMMAND}' git clone {REPO}")
        client2.succeed('test "$(cat repo/testfile | xargs echo -n)" = "hello world"')
        client.succeed("git clone ${remoteUri} /tmp/repo-clone")
        print(client.succeed("ls -lash /tmp/repo-clone"))
        assert "hello world" == client.succeed("cat /tmp/repo-clone/testfile").strip()

        with subtest("Testing git protocol version=2 over ssh"):
            git_protocol = client2.succeed(f"GIT_SSH_COMMAND='{GIT_SSH_COMMAND}' GIT_TRACE2_EVENT=true git -C repo fetch |& grep negotiated-version")
            git_protocol = client.succeed("GIT_TRACE2_EVENT=true git -C /tmp/repo-clone fetch |& grep negotiated-version")
            version = json.loads(git_protocol).get("value")
            assert version == "2", f"git did not negotiate protocol version 2, but version {version} instead."

@@ -164,7 +192,7 @@ let
            timeout=10
        )

        with subtest("Testing runner registration"):
        with subtest("Testing runner registration and action workflow"):
            server.succeed(
                "su -l forgejo -c 'GITEA_WORK_DIR=/var/lib/forgejo gitea actions generate-runner-token' | sed 's/^/TOKEN=/' | tee /var/lib/forgejo/runner_token"
            )
@@ -172,6 +200,52 @@ let
            server.wait_for_unit("gitea-runner-test.service")
            server.succeed("journalctl -o cat -u gitea-runner-test.service | grep -q 'Runner registered successfully'")

            # enable actions feature for this repository, defaults to disabled
            server.succeed(
                "curl --fail -X PATCH http://localhost:3000/api/v1/repos/test/repo "
                + "-H 'Accept: application/json' -H 'Content-Type: application/json' "
                + f"-H 'Authorization: token {api_token}'"
                + ' -d \'{"has_actions":true}\'''
            )

            # mirror "actions/checkout" action
            client.succeed("cp -R ${checkoutActionSource}/ /tmp/checkout")
            client.succeed("git -C /tmp/checkout init")
            client.succeed("git -C /tmp/checkout add .")
            client.succeed("git -C /tmp/checkout commit -m 'Initial import'")
            client.succeed("git -C /tmp/checkout remote add origin ${remoteUriCheckoutAction}")
            client.succeed("git -C /tmp/checkout push origin main")

            # push workflow to initial repo
            client.succeed("mkdir -p /tmp/repo/.forgejo/workflows")
            client.succeed("cp ${pkgs.writeText "dummy-workflow.yml" actionsWorkflowYaml} /tmp/repo/.forgejo/workflows/")
            client.succeed("git -C /tmp/repo add .")
            client.succeed("git -C /tmp/repo commit -m 'Add dummy workflow'")
            client.succeed("git -C /tmp/repo push origin main")

            def poll_workflow_action_status(_) -> bool:
                output = server.succeed(
                    "curl --fail http://localhost:3000/test/repo/actions | "
                    + 'htmlq ".flex-item-leading span" --attribute "data-tooltip-content"'
                ).strip()

                # values taken from https://codeberg.org/forgejo/forgejo/src/commit/af47c583b4fb3190fa4c4c414500f9941cc02389/options/locale/locale_en-US.ini#L3649-L3661
                if output in [ "Failure", "Canceled", "Skipped", "Blocked" ]:
                    raise Exception(f"Workflow status is '{output}', which we consider failed.")
                    server.log(f"Command returned '{output}', which we consider failed.")

                elif output in [ "Unknown", "Waiting", "Running", "" ]:
                    server.log(f"Workflow status is '{output}'. Waiting some more...")
                    return False

                elif output in [ "Success" ]:
                    return True

                raise Exception(f"Workflow status is '{output}', which we don't know. Value mappings likely need updating.")

            with server.nested("Waiting for the workflow run to be successful"):
                retry(poll_workflow_action_status)

        with subtest("Testing backup service"):
            server.succeed("${serverSystem}/specialisation/dump/bin/switch-to-configuration test")
            server.systemctl("start forgejo-dump")
@@ -181,4 +255,4 @@ let
  });
in

listToAttrs (map makeGForgejoTest supportedDbTypes)
listToAttrs (map makeForgejoTest supportedDbTypes)
+7 −3
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
, fetchFromGitea
, testers
, forgejo-runner
, nixosTests
}:

buildGoModule rec {
@@ -27,10 +28,13 @@ buildGoModule rec {

  doCheck = false; # Test try to lookup code.forgejo.org.

  passthru.tests.version = testers.testVersion {
  passthru.tests = {
    inherit (nixosTests.forgejo) sqlite3;
    version = testers.testVersion {
      package = forgejo-runner;
      version = src.rev;
    };
  };

  meta = with lib; {
    description = "A runner for Forgejo based on act";