def test_manifest_image_info_bad(tmp_path, monkeypatch): """The format of the image info environment variable is wrong.""" monkeypatch.setenv(IMAGE_INFO_ENV_VAR, "this is not a json") tstamp = datetime.datetime(2020, 2, 1, 15, 40, 33) with pytest.raises(CraftError) as cm: create_manifest(tmp_path, tstamp, None, []) exc = cm.value assert str(exc) == "Failed to parse the content of CHARMCRAFT_IMAGE_INFO environment variable" assert isinstance(exc.__cause__, json.JSONDecodeError)
def build_charm(self, bases_config: BasesConfiguration) -> str: """Build the charm. :param bases_config: Bases configuration to use for build. :returns: File name of charm. :raises CraftError: on lifecycle exception. :raises RuntimeError: on unexpected lifecycle exception. """ if env.is_charmcraft_running_in_managed_mode(): work_dir = env.get_managed_environment_home_path() else: work_dir = self.buildpath emit.progress(f"Building charm in {str(work_dir)!r}") if self._special_charm_part: # all current deprecated arguments set charm plugin parameters self._handle_deprecated_cli_arguments() # add charm files to the prime filter self._set_prime_filter() # set source if empty or not declared in charm part if not self._special_charm_part.get("source"): self._special_charm_part["source"] = str(self.charmdir) # run the parts lifecycle emit.trace(f"Parts definition: {self._parts}") lifecycle = parts.PartsLifecycle( self._parts, work_dir=work_dir, project_dir=self.charmdir, project_name=self.metadata.name, ignore_local_sources=["*.charm"], ) lifecycle.run(Step.PRIME) # run linters and show the results linting_results = linters.analyze(self.config, lifecycle.prime_dir) self.show_linting_results(linting_results) create_manifest( lifecycle.prime_dir, self.config.project.started_at, bases_config, linting_results, ) zipname = self.handle_package(lifecycle.prime_dir, bases_config) emit.message(f"Created '{zipname}'.", intermediate=True) return zipname
def _pack_bundle(self): """Pack a bundle.""" project = self.config.project config_parts = self.config.parts.copy() bundle_part = config_parts.setdefault("bundle", {}) prime = bundle_part.setdefault("prime", []) # get the config files bundle_filepath = project.dirpath / "bundle.yaml" bundle_config = load_yaml(bundle_filepath) if bundle_config is None: raise CommandError( "Missing or invalid main bundle file: {!r}.".format(str(bundle_filepath)) ) bundle_name = bundle_config.get("name") if not bundle_name: raise CommandError( "Invalid bundle config; missing a 'name' field indicating the bundle's name in " "file {!r}.".format(str(bundle_filepath)) ) # set prime filters for fname in MANDATORY_FILES: fpath = project.dirpath / fname if not fpath.exists(): raise CommandError("Missing mandatory file: {!r}.".format(str(fpath))) prime.extend(MANDATORY_FILES) # set source for buiding bundle_part["source"] = str(project.dirpath) # run the parts lifecycle logger.debug("Parts definition: %s", config_parts) lifecycle = parts.PartsLifecycle( config_parts, work_dir=project.dirpath / build.BUILD_DIRNAME, ignore_local_sources=[bundle_name + ".zip"], ) lifecycle.run(Step.PRIME) # pack everything create_manifest(lifecycle.prime_dir, project.started_at, None, []) zipname = project.dirpath / (bundle_name + ".zip") build_zip(zipname, lifecycle.prime_dir) logger.info("Created %r.", str(zipname))
def test_manifest_image_info_ok(tmp_path, monkeypatch): """Include the image info in the manifest.""" test_image_content = {"some info": ["whatever", 123]} monkeypatch.setenv(IMAGE_INFO_ENV_VAR, json.dumps(test_image_content)) tstamp = datetime.datetime(2020, 2, 1, 15, 40, 33) os_platform = OSPlatform(system="SuperUbuntu", release="40.10", machine="SomeRISC") with patch("charmcraft.utils.get_os_platform", return_value=os_platform): result_filepath = create_manifest(tmp_path, tstamp, None, []) saved = yaml.safe_load(result_filepath.read_text()) assert saved["image-info"] == test_image_content
def build_charm(self, bases_config: BasesConfiguration) -> str: """Build the charm. :param bases_config: Bases configuration to use for build. :returns: File name of charm. """ logger.debug("Building charm in %r", str(self.buildpath)) self._handle_deprecated_cli_arguments() # add charm files to the prime filter self._set_prime_filter() # set source for buiding self._charm_part["source"] = str(self.charmdir) # run the parts lifecycle logger.debug("Parts definition: %s", self._parts) lifecycle = parts.PartsLifecycle( self._parts, work_dir=self.buildpath, ignore_local_sources=["*.charm"], ) lifecycle.run(Step.PRIME) # run linters and show the results linting_results = linters.analyze(self.config, lifecycle.prime_dir) self.show_linting_results(linting_results) create_manifest( lifecycle.prime_dir, self.config.project.started_at, bases_config, linting_results, ) zipname = self.handle_package(lifecycle.prime_dir, bases_config) logger.info("Created '%s'.", zipname) return zipname
def test_manifest_no_bases(tmp_path): """Manifest without bases (used for bundles).""" tstamp = datetime.datetime(2020, 2, 1, 15, 40, 33) os_platform = OSPlatform(system="SuperUbuntu", release="40.10", machine="SomeRISC") with patch("charmcraft.utils.get_os_platform", return_value=os_platform): result_filepath = create_manifest(tmp_path, tstamp, None, []) saved = yaml.safe_load(result_filepath.read_text()) assert result_filepath == tmp_path / "manifest.yaml" assert saved == { "charmcraft-started-at": "2020-02-01T15:40:33Z", "charmcraft-version": __version__, "analysis": {"attributes": []}, }
def test_manifest_checkers_multiple(tmp_path): """Multiple checkers, attributes and a linter.""" linting_results = [ linters.CheckResult( name="attrib-name-1", check_type=linters.CheckType.attribute, url="url", text="text", result="result-1", ), linters.CheckResult( name="attrib-name-2", check_type=linters.CheckType.attribute, url="url", text="text", result="result-2", ), linters.CheckResult( name="warning-name", check_type=linters.CheckType.lint, url="url", text="text", result="result", ), ] tstamp = datetime.datetime(2020, 2, 1, 15, 40, 33) os_platform = OSPlatform(system="SuperUbuntu", release="40.10", machine="SomeRISC") with patch("charmcraft.utils.get_os_platform", return_value=os_platform): result_filepath = create_manifest(tmp_path, tstamp, None, linting_results) assert result_filepath == tmp_path / "manifest.yaml" saved = yaml.safe_load(result_filepath.read_text()) expected = [ { "name": "attrib-name-1", "result": "result-1", }, { "name": "attrib-name-2", "result": "result-2", }, ] assert saved["analysis"]["attributes"] == expected
def _pack_bundle(self, parsed_args) -> List[pathlib.Path]: """Pack a bundle.""" emit.progress("Packing the bundle.") if parsed_args.shell: build.launch_shell() return [] project = self.config.project if self.config.parts: config_parts = self.config.parts.copy() else: # "parts" not declared, create an implicit "bundle" part config_parts = {"bundle": {"plugin": "bundle"}} # a part named "bundle" using plugin "bundle" is special and has # predefined values set automatically. bundle_part = config_parts.get("bundle") if bundle_part and bundle_part.get("plugin") == "bundle": special_bundle_part = bundle_part else: special_bundle_part = None # get the config files bundle_filepath = project.dirpath / "bundle.yaml" bundle_config = load_yaml(bundle_filepath) if bundle_config is None: raise CraftError( "Missing or invalid main bundle file: {!r}.".format( str(bundle_filepath))) bundle_name = bundle_config.get("name") if not bundle_name: raise CraftError( "Invalid bundle config; missing a 'name' field indicating the bundle's name in " "file {!r}.".format(str(bundle_filepath))) if special_bundle_part: # set prime filters for fname in MANDATORY_FILES: fpath = project.dirpath / fname if not fpath.exists(): raise CraftError("Missing mandatory file: {!r}.".format( str(fpath))) prime = special_bundle_part.setdefault("prime", []) prime.extend(MANDATORY_FILES) # set source if empty or not declared in charm part if not special_bundle_part.get("source"): special_bundle_part["source"] = str(project.dirpath) if env.is_charmcraft_running_in_managed_mode(): work_dir = env.get_managed_environment_home_path() else: work_dir = project.dirpath / build.BUILD_DIRNAME # run the parts lifecycle emit.trace(f"Parts definition: {config_parts}") lifecycle = parts.PartsLifecycle( config_parts, work_dir=work_dir, project_dir=project.dirpath, project_name=bundle_name, ignore_local_sources=[bundle_name + ".zip"], ) try: lifecycle.run(Step.PRIME) except (RuntimeError, CraftError) as error: if parsed_args.debug: emit.trace(f"Error when running PRIME step: {error}") build.launch_shell() raise # pack everything create_manifest(lifecycle.prime_dir, project.started_at, None, []) zipname = project.dirpath / (bundle_name + ".zip") build_zip(zipname, lifecycle.prime_dir) emit.message(f"Created {str(zipname)!r}.") if parsed_args.shell_after: build.launch_shell() return [zipname]
def test_manifest_simple_ok(tmp_path): """Simple construct.""" bases_config = config.BasesConfiguration( **{ "build-on": [ config.Base( name="test-name", channel="test-channel", ), ], "run-on": [ config.Base( name="test-name", channel="test-channel", architectures=["arch1"], ), config.Base( name="test-name2", channel="test-channel2", architectures=["arch1", "arch2"], ), ], } ) linting_results = [ linters.CheckResult( name="check-name", check_type=linters.CheckType.attribute, url="url", text="text", result="check-result", ), ] tstamp = datetime.datetime(2020, 2, 1, 15, 40, 33) os_platform = OSPlatform(system="SuperUbuntu", release="40.10", machine="SomeRISC") with patch("charmcraft.utils.get_os_platform", return_value=os_platform): result_filepath = create_manifest(tmp_path, tstamp, bases_config, linting_results) assert result_filepath == tmp_path / "manifest.yaml" saved = yaml.safe_load(result_filepath.read_text()) expected = { "charmcraft-started-at": "2020-02-01T15:40:33Z", "charmcraft-version": __version__, "bases": [ { "name": "test-name", "channel": "test-channel", "architectures": ["arch1"], }, { "name": "test-name2", "channel": "test-channel2", "architectures": ["arch1", "arch2"], }, ], "analysis": { "attributes": [ { "name": "check-name", "result": "check-result", }, ], }, } assert saved == expected