about summary refs log tree commit diff
path: root/nixos/tests/forgejo.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/tests/forgejo.nix')
-rw-r--r--nixos/tests/forgejo.nix156
1 files changed, 115 insertions, 41 deletions
diff --git a/nixos/tests/forgejo.nix b/nixos/tests/forgejo.nix
index b14df0a2c74f9..8b9ee46ff5d32 100644
--- a/nixos/tests/forgejo.nix
+++ b/nixos/tests/forgejo.nix
@@ -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,21 +55,28 @@ 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" = {
-            enable = true;
-            name = "ci";
-            url = "http://localhost:3000";
-            labels = [
-              # don't require docker/podman
-              "native:host"
-            ];
-            tokenFile = "/var/lib/forgejo/runner_token";
+          configuration.services.gitea-actions-runner = {
+            package = pkgs.forgejo-runner;
+            instances."test" = {
+              enable = true;
+              name = "ci";
+              url = "http://localhost:3000";
+              labels = [
+                # type ":host" does not depend on docker/podman/lxc
+                "native:host"
+              ];
+              tokenFile = "/var/lib/forgejo/runner_token";
+            };
           };
         };
         specialisation.dump = {
@@ -62,11 +88,20 @@ let
           };
         };
       };
-      client1 = { config, pkgs, ... }: {
-        environment.systemPackages = [ pkgs.git ];
-      };
-      client2 = { config, pkgs, ... }: {
-        environment.systemPackages = [ pkgs.git ];
+      client = { ... }: {
+        programs.git = {
+          enable = true;
+          config = {
+            user.email = "test@localhost";
+            user.name = "test";
+            init.defaultBranch = "main";
+          };
+        };
+        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)