Merge ~jugmac00/lpci:add-golang-plugin into lpci:main

Proposed by Jürgen Gmach
Status: Merged
Merged at revision: ff5b53ac785092fb4d79fbba9fd119240d90badc
Proposed branch: ~jugmac00/lpci:add-golang-plugin
Merge into: lpci:main
Diff against target: 231 lines (+178/-2)
4 files modified
NEWS.rst (+5/-0)
lpcraft/plugin/tests/test_plugins.py (+120/-1)
lpcraft/plugins/plugins.py (+52/-0)
setup.cfg (+1/-1)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+427068@code.launchpad.net

Commit message

Add Golang plugin

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) wrote :

I was not sure whether it makes sense to enter any invalid value to the version field, as the validator converts everything to string and in case that was not a valid golang version, the user gets a proper message in the error log.

I could add e.g. a value of `[1.18]` to the version field, which is not valid, and which would result in lpcraft trying to install `golang-[1.18]`...

Revision history for this message
Colin Watson (cjwatson) :
review: Approve
Revision history for this message
Jürgen Gmach (jugmac00) wrote :

Thanks for the review!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/NEWS.rst b/NEWS.rst
2index 924486c..3c3b4d6 100644
3--- a/NEWS.rst
4+++ b/NEWS.rst
5@@ -2,6 +2,11 @@
6 Version history
7 ===============
8
9+0.0.21 (unreleased)
10+===================
11+
12+- Add Golang plugin.
13+
14 0.0.20 (2022-07-15)
15 ===================
16
17diff --git a/lpcraft/plugin/tests/test_plugins.py b/lpcraft/plugin/tests/test_plugins.py
18index 5b28fd7..3a9a357 100644
19--- a/lpcraft/plugin/tests/test_plugins.py
20+++ b/lpcraft/plugin/tests/test_plugins.py
21@@ -10,7 +10,7 @@ from unittest.mock import ANY, Mock, call, patch
22
23 from craft_providers.lxd import launch
24 from fixtures import TempDir
25-from pydantic import StrictStr, validator
26+from pydantic import StrictStr, ValidationError, validator
27
28 import lpcraft.config
29 from lpcraft.commands.tests import CommandBaseTestCase
30@@ -961,3 +961,122 @@ class TestPlugins(CommandBaseTestCase):
31 )
32
33 self.assertEqual(0, result.exit_code)
34+
35+ @patch("lpcraft.commands.run.get_provider")
36+ @patch("lpcraft.commands.run.get_host_architecture", return_value="amd64")
37+ def test_golang_plugin(
38+ self, mock_get_host_architecture, mock_get_provider
39+ ):
40+ launcher = Mock(spec=launch)
41+ provider = makeLXDProvider(lxd_launcher=launcher)
42+ mock_get_provider.return_value = provider
43+ execute_run = launcher.return_value.execute_run
44+ execute_run.return_value = subprocess.CompletedProcess([], 0)
45+ config = dedent(
46+ """
47+ pipeline:
48+ - build
49+
50+ jobs:
51+ build:
52+ plugin: golang
53+ golang-version: "1.17"
54+ series: focal
55+ architectures: amd64
56+ packages: [file, git]
57+ run: go build -x examples/go-top.go
58+ """
59+ )
60+ Path(".launchpad.yaml").write_text(config)
61+
62+ self.run_command("run")
63+ self.assertEqual(
64+ [
65+ call(
66+ ["apt", "update"],
67+ cwd=PosixPath("/root/lpcraft/project"),
68+ env={},
69+ stdout=ANY,
70+ stderr=ANY,
71+ ),
72+ call(
73+ ["apt", "install", "-y", "golang-1.17", "file", "git"],
74+ cwd=PosixPath("/root/lpcraft/project"),
75+ env={},
76+ stdout=ANY,
77+ stderr=ANY,
78+ ),
79+ call(
80+ [
81+ "bash",
82+ "--noprofile",
83+ "--norc",
84+ "-ec",
85+ "\nexport PATH=/usr/lib/go-1.17/bin/:$PATH\ngo build -x examples/go-top.go", # noqa: E501
86+ ],
87+ cwd=PosixPath("/root/lpcraft/project"),
88+ env={},
89+ stdout=ANY,
90+ stderr=ANY,
91+ ),
92+ ],
93+ execute_run.call_args_list,
94+ )
95+
96+ @patch("lpcraft.commands.run.get_provider")
97+ @patch("lpcraft.commands.run.get_host_architecture", return_value="amd64")
98+ def test_golang_plugin_with_illegal_version(
99+ self, mock_get_host_architecture, mock_get_provider
100+ ):
101+ launcher = Mock(spec=launch)
102+ provider = makeLXDProvider(lxd_launcher=launcher)
103+ mock_get_provider.return_value = provider
104+ execute_run = launcher.return_value.execute_run
105+ execute_run.return_value = subprocess.CompletedProcess([], 0)
106+ # we do not allow floats as e.g. `1.20` is a problematic value in YAML
107+ config = dedent(
108+ """
109+ pipeline:
110+ - build
111+ jobs:
112+ build:
113+ plugin: golang
114+ golang-version: 1.18
115+ series: focal
116+ architectures: amd64
117+ packages: [file, git]
118+ run: go build -x examples/go-top.go
119+ """
120+ )
121+ Path(".launchpad.yaml").write_text(config)
122+
123+ result = self.run_command("run")
124+
125+ self.assertEqual(1, result.exit_code)
126+
127+ [error] = result.errors
128+ self.assertIn("str type expected", str(error))
129+
130+ def test_load_golang_plugin_configuration_with_invalid_version(self):
131+ config = dedent(
132+ """
133+ pipeline:
134+ - build
135+ jobs:
136+ build:
137+ plugin: golang
138+ golang-version: 1.18
139+ series: focal
140+ architectures: amd64
141+ packages: [file, git]
142+ run: go build -x examples/go-top.go
143+ """
144+ )
145+ config_path = Path(".launchpad.yaml")
146+ config_path.write_text(config)
147+
148+ self.assertRaises(
149+ ValidationError,
150+ lpcraft.config.Config.load,
151+ config_path,
152+ )
153diff --git a/lpcraft/plugins/plugins.py b/lpcraft/plugins/plugins.py
154index 833c461..d4464ee 100644
155--- a/lpcraft/plugins/plugins.py
156+++ b/lpcraft/plugins/plugins.py
157@@ -8,6 +8,7 @@ __all__ = [
158 "PyProjectBuildPlugin",
159 "MiniCondaPlugin",
160 "CondaBuildPlugin",
161+ "GolangPlugin",
162 ]
163
164 import textwrap
165@@ -399,3 +400,54 @@ class CondaBuildPlugin(MiniCondaPlugin):
166 {build_command}{conda_channels}{configs} {self.build_target}
167 {run_command}"""
168 )
169+
170+
171+@register(name="golang")
172+class GolangPlugin(BasePlugin):
173+ """Installs the required `golang` version.
174+
175+ Usage:
176+ In `.launchpad.yaml`, create the following structure. Please note that
177+ the `golang-version` has to be a string.
178+
179+ .. code-block:: yaml
180+
181+ pipeline:
182+ - build
183+
184+ jobs:
185+ build:
186+ plugin: golang
187+ golang-version: "1.17"
188+ series: focal
189+ architectures: amd64
190+ packages: [file, git]
191+ run: go build -x examples/go-top.go
192+
193+ Please note that the requested golang package needs to be available
194+ either in the standard repository or in a repository specified in
195+ `package-repositories`.
196+ """
197+
198+ class Config(BaseConfig):
199+ golang_version: StrictStr
200+
201+ INTERPOLATES_RUN_COMMAND = True
202+
203+ def get_plugin_config(self) -> "GolangPlugin.Config":
204+ return cast(GolangPlugin.Config, self.config.plugin_config)
205+
206+ @hookimpl # type: ignore
207+ def lpcraft_install_packages(self) -> list[str]:
208+ version = self.get_plugin_config().golang_version
209+ return [f"golang-{version}"]
210+
211+ @hookimpl # type: ignore
212+ def lpcraft_execute_run(self) -> str:
213+ version = self.get_plugin_config().golang_version
214+ run_command = self.config.run or ""
215+ return textwrap.dedent(
216+ f"""
217+ export PATH=/usr/lib/go-{version}/bin/:$PATH
218+ {run_command}"""
219+ )
220diff --git a/setup.cfg b/setup.cfg
221index 620de17..76d03ce 100644
222--- a/setup.cfg
223+++ b/setup.cfg
224@@ -1,6 +1,6 @@
225 [metadata]
226 name = lpcraft
227-version = 0.0.20
228+version = 0.0.21.dev0
229 description = Runner for Launchpad CI jobs
230 long_description = file: README.rst
231 long_description_content_type = text/x-rst

Subscribers

People subscribed via source and target branches