diff --git a/doc/source/go-jobs.rst b/doc/source/go-jobs.rst
new file mode 100644
index 000000000..f6225713a
--- /dev/null
+++ b/doc/source/go-jobs.rst
@@ -0,0 +1,5 @@
+Go Jobs
+=======
+
+.. zuul:autojob:: golang-go
+.. zuul:autojob:: golang-go-test
diff --git a/doc/source/go-roles.rst b/doc/source/go-roles.rst
new file mode 100644
index 000000000..c6ed2d7ff
--- /dev/null
+++ b/doc/source/go-roles.rst
@@ -0,0 +1,5 @@
+Go Roles
+========
+
+.. zuul:autorole:: install-go
+.. zuul:autorole:: go
diff --git a/doc/source/jobs.rst b/doc/source/jobs.rst
index b1141eb86..a02137301 100644
--- a/doc/source/jobs.rst
+++ b/doc/source/jobs.rst
@@ -8,3 +8,4 @@ Jobs
    python-jobs
    js-jobs
    docker-jobs
+   go-jobs
diff --git a/doc/source/roles.rst b/doc/source/roles.rst
index 89be8f5b6..6c8f9c096 100644
--- a/doc/source/roles.rst
+++ b/doc/source/roles.rst
@@ -11,6 +11,7 @@ Roles
    cloud-roles
    deprecated-roles
    galaxy-roles
+   go-roles
    js-roles
    launchpad-roles
    puppet-roles
diff --git a/playbooks/go/pre.yaml b/playbooks/go/pre.yaml
new file mode 100644
index 000000000..9ab00c00b
--- /dev/null
+++ b/playbooks/go/pre.yaml
@@ -0,0 +1,3 @@
+- hosts: all
+  roles:
+    - install-go
diff --git a/playbooks/go/run.yaml b/playbooks/go/run.yaml
new file mode 100644
index 000000000..e1296000d
--- /dev/null
+++ b/playbooks/go/run.yaml
@@ -0,0 +1,4 @@
+- hosts: all
+  roles:
+    - revoke-sudo
+    - go
diff --git a/roles/go/README.rst b/roles/go/README.rst
new file mode 100644
index 000000000..8fc8359b4
--- /dev/null
+++ b/roles/go/README.rst
@@ -0,0 +1,24 @@
+Run go command in a source directory. Assumes the appropriate version
+of go has been installed.
+
+**Role Variables**
+
+.. zuul:rolevar:: go_command
+
+   Go command to run.
+   This parameter is mandatory.
+   Examples are "test", "run" or "build"
+
+.. zuul:rolevar:: go_package_dir
+
+   Directory of the affected go package.
+
+.. zuul:rolevar:: go_bin_path
+   :default: {{ go_install_dir }}/go/bin
+
+   Path to go bin directory
+
+.. zuul:rolevar:: zuul_work_dir
+   :default: {{ zuul.project.src_dir }}
+
+   Directory to run go in.
diff --git a/roles/go/defaults/main.yaml b/roles/go/defaults/main.yaml
new file mode 100644
index 000000000..50f8d8dc6
--- /dev/null
+++ b/roles/go/defaults/main.yaml
@@ -0,0 +1,3 @@
+zuul_work_dir: "{{ zuul.project.src_dir }}"
+go_install_dir: "/usr/local"
+go_bin_path: "{{ go_install_dir }}/go/bin"
diff --git a/roles/go/tasks/main.yaml b/roles/go/tasks/main.yaml
new file mode 100644
index 000000000..a5b3deadb
--- /dev/null
+++ b/roles/go/tasks/main.yaml
@@ -0,0 +1,13 @@
+- name: Require go_command variable
+  fail:
+    msg: go_command is required for this role
+  when: go_command is not defined
+
+- name: Run go command
+  command: >-
+    go {{ go_command }}
+    {% if go_package_dir is defined %}'./{{ go_package_dir }}'{% endif %}
+  args:
+    chdir: "{{ zuul_work_dir }}"
+  environment:
+    PATH: "{{ ansible_env.PATH }}:{{ go_bin_path }}"
diff --git a/roles/install-go/README.rst b/roles/install-go/README.rst
new file mode 100644
index 000000000..169d3a728
--- /dev/null
+++ b/roles/install-go/README.rst
@@ -0,0 +1,17 @@
+Install go
+
+**Role Variables**
+
+.. zuul:rolevar:: go_install_dir
+   :default: /usr/local/
+
+   Directory to install go in.
+
+.. zuul:rolevar:: go_version
+   :default: 1.13
+
+.. zuul:rolevar:: go_os
+   :default: {{ ansible_system | lower }}
+
+.. zuul:rolevar:: go_arch
+   :default: amd64 / 386
diff --git a/roles/install-go/defaults/main.yaml b/roles/install-go/defaults/main.yaml
new file mode 100644
index 000000000..392228438
--- /dev/null
+++ b/roles/install-go/defaults/main.yaml
@@ -0,0 +1,4 @@
+go_version: "1.13"
+go_os: "{{ ansible_system | lower }}"
+go_arch: "{{ go_arch_translation[ansible_architecture] }}"
+go_install_dir: "/usr/local"
diff --git a/roles/install-go/tasks/main.yaml b/roles/install-go/tasks/main.yaml
new file mode 100644
index 000000000..1b2284214
--- /dev/null
+++ b/roles/install-go/tasks/main.yaml
@@ -0,0 +1,39 @@
+- name: Check installed go version
+  command: go version
+  register: go_installed_version
+  environment:
+    PATH: "{{ ansible_env.PATH }}:{{ go_install_dir }}/go/bin"
+  ignore_errors: yes
+
+- name: Skip if correct version of go is installed
+  meta: end_host
+  when:
+    - go_installed_version.rc == 0
+    - go_version == (go_installed_version.stdout|regex_replace(go_version_pattern, '\\g<version>'))
+    - go_os == (go_installed_version.stdout|regex_replace(go_version_pattern, '\\g<os>'))
+    - go_arch == (go_installed_version.stdout|regex_replace(go_version_pattern, '\\g<arch>'))
+
+- name: Create temp directory
+  tempfile:
+    state: directory
+  register: go_archive_tempdir
+
+- name: Get archive checksum
+  uri:
+    url: "https://dl.google.com/go/go{{ go_version }}.{{ go_os }}-{{ go_arch }}.tar.gz.sha256"
+    return_content: true
+  register: go_archive_checksum
+
+
+- name: Download go archive
+  get_url:
+    url: "https://dl.google.com/go/go{{ go_version }}.{{ go_os }}-{{ go_arch }}.tar.gz"
+    dest: "{{ go_archive_tempdir.path }}/go{{ go_version }}.{{ go_os }}-{{ go_arch }}.tar.gz"
+    checksum: "sha256:{{ go_archive_checksum.content }}"
+
+- name: Install go
+  unarchive:
+    src: "{{ go_archive_tempdir.path }}/go{{ go_version }}.{{ go_os }}-{{ go_arch }}.tar.gz"
+    dest: "{{ go_install_dir }}"
+    remote_src: yes
+  become: true
diff --git a/roles/install-go/vars/main.yaml b/roles/install-go/vars/main.yaml
new file mode 100644
index 000000000..c99ce7ba0
--- /dev/null
+++ b/roles/install-go/vars/main.yaml
@@ -0,0 +1,6 @@
+go_arch_translation:
+  amd64: amd64
+  x86_64: amd64
+  i386: 386
+
+go_version_pattern: ^go version go(?P<version>.*?) (?P<os>.*?)/(?P<arch>.*?)$
diff --git a/zuul-tests.d/go-roles-jobs.yaml b/zuul-tests.d/go-roles-jobs.yaml
new file mode 100644
index 000000000..7e5a185ac
--- /dev/null
+++ b/zuul-tests.d/go-roles-jobs.yaml
@@ -0,0 +1,18 @@
+- job:
+    name: zuul-jobs-test-golang-go
+    parent: golang-go
+    description: Test the golang-go job
+    files:
+      - playbooks/go
+      - roles/install-go
+      - role/go
+      - zuul.d/go-jobs.yaml
+    vars:
+      go_command: version
+
+- project:
+    check:
+      jobs: &id001
+        - zuul-jobs-test-golang-go
+    gate:
+      jobs: *id001
diff --git a/zuul.d/go-jobs.yaml b/zuul.d/go-jobs.yaml
new file mode 100644
index 000000000..d43ca4fa0
--- /dev/null
+++ b/zuul.d/go-jobs.yaml
@@ -0,0 +1,92 @@
+# Jobs listed in go-jobs.rst.
+
+- job:
+    name: golang-go
+    parent: unittests
+    description: |
+      Base job for go operations
+
+      Responds to these variables:
+
+      .. zuul:jobvar:: go_command
+         :default: build
+
+         Command to pass to go.
+
+      .. zuul:jobvar:: go_package_dir
+
+         Path to go package to test
+
+      .. zuul:jobvar:: go_install_dir
+         :default: /usr/local/
+
+         Path to install go in
+
+      .. zuul:jobvar:: go_version
+         :default: 1.13
+
+         The version of go to use.
+
+      .. zuul:jobvar:: go_os
+         :default: {{ ansible_system | lower }}
+
+          OS to use when choosing go version.
+
+      .. zuul:jobvar:: go_arch
+         :default: amd64 / 386
+
+          Architecture to use when choosing go version
+
+      .. zuul:jobvar:: zuul_work_dir
+         :default: {{ zuul.project.src_dir }}
+
+         Path to operate in.
+
+    pre-run: playbooks/go/pre.yaml
+    run: playbooks/go/run.yaml
+    vars:
+      go_command: build
+
+- job:
+    name: golang-go-test
+    parent: golang-go
+    description: |
+      Base job for go operations
+
+      Responds to these variables:
+
+      .. zuul:jobvar:: go_command
+         :default: build
+
+         Command to pass to go.
+
+      .. zuul:jobvar:: go_package_dir
+
+         Path to go package to test
+
+      .. zuul:jobvar:: go_install_dir
+         :default: /usr/local/
+
+         Path to install go in
+
+      .. zuul:jobvar:: go_version
+         :default: 1.13
+
+         The version of go to use.
+
+      .. zuul:jobvar:: go_os
+         :default: {{ ansible_system | lower }}
+
+         OS to use when choosing go version.
+
+      .. zuul:jobvar:: go_arch
+         :default: amd64 / 386
+
+         Architecture to use when choosing go version
+
+      .. zuul:jobvar:: zuul_work_dir
+         :default: {{ zuul.project.src_dir }}
+
+         Path to operate in.
+    vars:
+      go_command: test