From 4fdc52c60cb9598e28895b9f27dff59f23c578ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 10 Nov 2020 15:59:32 +0100 Subject: Add support for publishing Hex releases and docs --- CHANGELOG.asciidoc | 4 + build.config | 1 + plugins/hex.mk | 336 +++++++++++++++++++++++++++++++++++++++ test/Makefile | 2 +- test/plugin_hex.mk | 457 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 799 insertions(+), 1 deletion(-) create mode 100644 plugins/hex.mk create mode 100644 test/plugin_hex.mk diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index f0ff0e2..f237592 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -23,3 +23,7 @@ 2020/06/18: Concuerror integration has been added. It is currently minimal but usable. Experimentation and feedback is welcome. + +2020/11/30: Support for publishing Hex releases and docs + has been added. It is currently experimental. + Feedback is more than welcome. diff --git a/build.config b/build.config index a0ab7a7..b363ef0 100644 --- a/build.config +++ b/build.config @@ -29,6 +29,7 @@ plugins/edoc plugins/erlydtl plugins/escript plugins/eunit +plugins/hex plugins/proper plugins/protobuffs plugins/relx diff --git a/plugins/hex.mk b/plugins/hex.mk new file mode 100644 index 0000000..b0a5339 --- /dev/null +++ b/plugins/hex.mk @@ -0,0 +1,336 @@ +# Copyright (c) 2020, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +HEX_CORE_GIT ?= https://github.com/hexpm/hex_core +HEX_CORE_COMMIT ?= v0.7.0 + +PACKAGES += hex_core +pkg_hex_core_name = hex_core +pkg_hex_core_description = Reference implementation of Hex specifications +pkg_hex_core_homepage = $(HEX_CORE_GIT) +pkg_hex_core_fetch = git +pkg_hex_core_repo = $(HEX_CORE_GIT) +pkg_hex_core_commit = $(HEX_CORE_COMMIT) + +# We automatically depend on hex_core when the project isn't already. +$(if $(filter hex_core,$(DEPS) $(BUILD_DEPS) $(DOC_DEPS) $(REL_DEPS) $(TEST_DEPS)),,\ + $(eval $(call dep_target,hex_core))) + +hex-core: $(DEPS_DIR)/hex_core + $(verbose) if [ ! -e $(DEPS_DIR)/hex_core/ebin/dep_built ]; then \ + $(MAKE) -C $(DEPS_DIR)/hex_core IS_DEP=1; \ + touch $(DEPS_DIR)/hex_core/ebin/dep_built; \ + fi + +# @todo This must also apply to fetching. +HEX_CONFIG ?= + +define hex_config.erl + begin + Config0 = hex_core:default_config(), + Config0$(HEX_CONFIG) + end +endef + +define hex_user_create.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + case hex_api_user:create(Config, <<"$(strip $1)">>, <<"$(strip $2)">>, <<"$(strip $3)">>) of + {ok, {201, _, #{<<"email">> := Email, <<"url">> := URL, <<"username">> := Username}}} -> + io:format("User ~s (~s) created at ~s~n" + "Please check your inbox for a confirmation email.~n" + "You must confirm before you are allowed to publish packages.~n", + [Username, Email, URL]), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(80) + end +endef + +# The $(info ) call inserts a new line after the password prompt. +hex-user-create: hex-core + $(if $(HEX_USERNAME),,$(eval HEX_USERNAME := $(shell read -p "Username: " username; echo $$username))) + $(if $(HEX_PASSWORD),,$(eval HEX_PASSWORD := $(shell stty -echo; read -p "Password: " password; stty echo; echo $$password) $(info ))) + $(if $(HEX_EMAIL),,$(eval HEX_EMAIL := $(shell read -p "Email: " email; echo $$email))) + $(gen_verbose) $(call erlang,$(call hex_user_create.erl,$(HEX_USERNAME),$(HEX_PASSWORD),$(HEX_EMAIL))) + +define hex_key_add.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + ConfigF = Config#{api_key => iolist_to_binary([<<"Basic ">>, base64:encode(<<"$(strip $1):$(strip $2)">>)])}, + Permissions = [ + case string:split(P, <<":">>) of + [D] -> #{domain => D}; + [D, R] -> #{domain => D, resource => R} + end + || P <- string:split(<<"$(strip $4)">>, <<",">>, all)], + case hex_api_key:add(ConfigF, <<"$(strip $3)">>, Permissions) of + {ok, {201, _, #{<<"secret">> := Secret}}} -> + io:format("Key ~s created for user ~s~nSecret: ~s~n" + "Please store the secret in a secure location, such as a password store.~n" + "The secret will be requested for most Hex-related operations.~n", + [<<"$(strip $3)">>, <<"$(strip $1)">>, Secret]), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(81) + end +endef + +hex-key-add: hex-core + $(if $(HEX_USERNAME),,$(eval HEX_USERNAME := $(shell read -p "Username: " username; echo $$username))) + $(if $(HEX_PASSWORD),,$(eval HEX_PASSWORD := $(shell stty -echo; read -p "Password: " password; stty echo; echo $$password) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_key_add.erl,$(HEX_USERNAME),$(HEX_PASSWORD),\ + $(if $(name),$(name),$(shell hostname)-erlang-mk),\ + $(if $(perm),$(perm),api))) + +HEX_TARBALL_EXTRA_METADATA ?= + +# @todo Check that we can += files +HEX_TARBALL_FILES ?= \ + $(wildcard early-plugins.mk) \ + $(wildcard ebin/$(PROJECT).app) \ + $(wildcard ebin/$(PROJECT).appup) \ + $(wildcard $(notdir $(ERLANG_MK_FILENAME))) \ + $(sort $(call core_find,include/,*.hrl)) \ + $(wildcard LICENSE*) \ + $(wildcard Makefile) \ + $(wildcard plugins.mk) \ + $(sort $(call core_find,priv/,*)) \ + $(wildcard README*) \ + $(wildcard rebar.config) \ + $(sort $(call core_find,src/,*)) + +HEX_TARBALL_OUTPUT_FILE ?= $(ERLANG_MK_TMP)/$(PROJECT).tar + +# @todo Need to check for rebar.config and/or the absence of DEPS to know +# whether a project will work with Rebar. +# +# @todo contributors licenses links in HEX_TARBALL_EXTRA_METADATA + +# In order to build the requirements metadata we look into DEPS. +# We do not require that the project use Hex dependencies, however +# Hex.pm does require that the package name and version numbers +# correspond to a real Hex package. +define hex_tarball_create.erl + Files0 = [$(call comma_list,$(patsubst %,"%",$(HEX_TARBALL_FILES)))], + Requirements0 = #{ + $(foreach d,$(DEPS), + <<"$(if $(subst hex,,$(call query_fetch_method,$d)),$d,$(if $(word 3,$(dep_$d)),$(word 3,$(dep_$d)),$d))">> => #{ + <<"app">> => <<"$d">>, + <<"optional">> => false, + <<"requirement">> => <<"$(call query_version,$d)">> + },) + $(if $(DEPS),dummy => dummy) + }, + Requirements = maps:remove(dummy, Requirements0), + Metadata0 = #{ + app => <<"$(strip $(PROJECT))">>, + build_tools => [<<"make">>, <<"rebar3">>], + description => <<"$(strip $(PROJECT_DESCRIPTION))">>, + files => [unicode:characters_to_binary(F) || F <- Files0], + name => <<"$(strip $(PROJECT))">>, + requirements => Requirements, + version => <<"$(strip $(PROJECT_VERSION))">> + }, + Metadata = Metadata0$(HEX_TARBALL_EXTRA_METADATA), + Files = [case file:read_file(F) of + {ok, Bin} -> + {F, Bin}; + {error, Reason} -> + io:format("Error trying to open file ~0p: ~0p~n", [F, Reason]), + halt(82) + end || F <- Files0], + case hex_tarball:create(Metadata, Files) of + {ok, #{tarball := Tarball}} -> + ok = file:write_file("$(strip $(HEX_TARBALL_OUTPUT_FILE))", Tarball), + halt(0); + {error, Reason} -> + io:format("Error ~0p~n", [Reason]), + halt(83) + end +endef + +hex_tar_verbose_0 = @echo " TAR $(notdir $(ERLANG_MK_TMP))/$(@F)"; +hex_tar_verbose_2 = set -x; +hex_tar_verbose = $(hex_tar_verbose_$(V)) + +$(HEX_TARBALL_OUTPUT_FILE): hex-core app + $(hex_tar_verbose) $(call erlang,$(call hex_tarball_create.erl)) + +hex-tarball-create: $(HEX_TARBALL_OUTPUT_FILE) + +define hex_release_publish_summary.erl + {ok, Tarball} = erl_tar:open("$(strip $(HEX_TARBALL_OUTPUT_FILE))", [read]), + ok = erl_tar:extract(Tarball, [{cwd, "$(ERLANG_MK_TMP)"}, {files, ["metadata.config"]}]), + {ok, Metadata} = file:consult("$(ERLANG_MK_TMP)/metadata.config"), + #{ + <<"name">> := Name, + <<"version">> := Version, + <<"files">> := Files, + <<"requirements">> := Deps + } = maps:from_list(Metadata), + io:format("Publishing ~s ~s~n Dependencies:~n", [Name, Version]), + case Deps of + [] -> + io:format(" (none)~n"); + _ -> + [begin + #{<<"app">> := DA, <<"requirement">> := DR} = maps:from_list(D), + io:format(" ~s ~s~n", [DA, DR]) + end || {_, D} <- Deps] + end, + io:format(" Included files:~n"), + [io:format(" ~s~n", [F]) || F <- Files], + io:format("You may also review the contents of the tarball file.~n" + "Please enter your secret key to proceed.~n"), + halt(0) +endef + +define hex_release_publish.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + ConfigF = Config#{api_key => <<"$(strip $1)">>}, + {ok, Tarball} = file:read_file("$(strip $(HEX_TARBALL_OUTPUT_FILE))"), + case hex_api_release:publish(ConfigF, Tarball, [{replace, $2}]) of + {ok, {200, _, #{}}} -> + io:format("Release replaced~n"), + halt(0); + {ok, {201, _, #{}}} -> + io:format("Release published~n"), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(84) + end +endef + +hex-release-tarball: hex-core $(HEX_TARBALL_OUTPUT_FILE) + $(verbose) $(call erlang,$(call hex_release_publish_summary.erl)) + +hex-release-publish: hex-core hex-release-tarball + $(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_release_publish.erl,$(HEX_SECRET),false)) + +hex-release-replace: hex-core hex-release-tarball + $(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_release_publish.erl,$(HEX_SECRET),true)) + +define hex_release_delete.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + ConfigF = Config#{api_key => <<"$(strip $1)">>}, + case hex_api_release:delete(ConfigF, <<"$(strip $(PROJECT))">>, <<"$(strip $(PROJECT_VERSION))">>) of + {ok, {204, _, _}} -> + io:format("Release $(strip $(PROJECT_VERSION)) deleted~n"), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(85) + end +endef + +hex-release-delete: hex-core + $(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_release_delete.erl,$(HEX_SECRET))) + +define hex_release_retire.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + ConfigF = Config#{api_key => <<"$(strip $1)">>}, + Params = #{<<"reason">> => <<"$(strip $3)">>, <<"message">> => <<"$(strip $4)">>}, + case hex_api_release:retire(ConfigF, <<"$(strip $(PROJECT))">>, <<"$(strip $2)">>, Params) of + {ok, {204, _, _}} -> + io:format("Release $(strip $2) has been retired~n"), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(86) + end +endef + +hex-release-retire: hex-core + $(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_release_retire.erl,$(HEX_SECRET),\ + $(if $(HEX_VERSION),$(HEX_VERSION),$(PROJECT_VERSION)),\ + $(if $(HEX_REASON),$(HEX_REASON),invalid),\ + $(HEX_MESSAGE))) + +define hex_release_unretire.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + ConfigF = Config#{api_key => <<"$(strip $1)">>}, + case hex_api_release:unretire(ConfigF, <<"$(strip $(PROJECT))">>, <<"$(strip $2)">>) of + {ok, {204, _, _}} -> + io:format("Release $(strip $2) is not retired anymore~n"), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(87) + end +endef + +hex-release-unretire: hex-core + $(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_release_unretire.erl,$(HEX_SECRET),\ + $(if $(HEX_VERSION),$(HEX_VERSION),$(PROJECT_VERSION)))) + +HEX_DOCS_DOC_DIR ?= doc/ +HEX_DOCS_TARBALL_FILES ?= $(sort $(call core_find,$(HEX_DOCS_DOC_DIR),*)) +HEX_DOCS_TARBALL_OUTPUT_FILE ?= $(ERLANG_MK_TMP)/$(PROJECT)-docs.tar.gz + +$(HEX_DOCS_TARBALL_OUTPUT_FILE): hex-core app docs + $(hex_tar_verbose) tar czf $(HEX_DOCS_TARBALL_OUTPUT_FILE) -C $(HEX_DOCS_DOC_DIR) \ + $(HEX_DOCS_TARBALL_FILES:$(HEX_DOCS_DOC_DIR)%=%) + +hex-docs-tarball-create: $(HEX_DOCS_TARBALL_OUTPUT_FILE) + +define hex_docs_publish.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + ConfigF = Config#{api_key => <<"$(strip $1)">>}, + {ok, Tarball} = file:read_file("$(strip $(HEX_DOCS_TARBALL_OUTPUT_FILE))"), + case hex_api:post(ConfigF, + ["packages", "$(strip $(PROJECT))", "releases", "$(strip $(PROJECT_VERSION))", "docs"], + {"application/octet-stream", Tarball}) of + {ok, {Status, _, _}} when Status >= 200, Status < 300 -> + io:format("Docs published~n"), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(88) + end +endef + +hex-docs-publish: hex-core hex-docs-tarball-create + $(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_docs_publish.erl,$(HEX_SECRET))) + +define hex_docs_delete.erl + {ok, _} = application:ensure_all_started(ssl), + {ok, _} = application:ensure_all_started(inets), + Config = $(hex_config.erl), + ConfigF = Config#{api_key => <<"$(strip $1)">>}, + case hex_api:delete(ConfigF, + ["packages", "$(strip $(PROJECT))", "releases", "$(strip $2)", "docs"]) of + {ok, {Status, _, _}} when Status >= 200, Status < 300 -> + io:format("Docs removed~n"), + halt(0); + {ok, {Status, _, Errors}} -> + io:format("Error ~b: ~0p~n", [Status, Errors]), + halt(89) + end +endef + +hex-docs-delete: hex-core + $(if $(HEX_SECRET),,$(eval HEX_SECRET := $(shell stty -echo; read -p "Secret: " secret; stty echo; echo $$secret) $(info ))) + $(gen_verbose) $(call erlang,$(call hex_docs_delete.erl,$(HEX_SECRET),\ + $(if $(HEX_VERSION),$(HEX_VERSION),$(PROJECT_VERSION)))) diff --git a/test/Makefile b/test/Makefile index 4a8b5e3..8d1a5e8 100644 --- a/test/Makefile +++ b/test/Makefile @@ -124,7 +124,7 @@ endef all:: core clean:: - $t rm -rf erl_crash.dump packages/ test_*/ + $t rm -rf erl_crash.dump packages/ $(filter-out test_rebar_git/,$(wildcard test_*/)) init: clean $i "Prefetch Rebar if necessary" diff --git a/test/plugin_hex.mk b/test/plugin_hex.mk new file mode 100644 index 0000000..66bf6fc --- /dev/null +++ b/test/plugin_hex.mk @@ -0,0 +1,457 @@ +# Hex plugin. +# +# In order to run these tests, a local Hex.pm instance must +# be started and available on port 4000, and the HEX=1 variable +# must be set. + +HEX_TARGETS = $(call list_targets,hex) + +.PHONY: hex $(HEX_TARGETS) + +hex: $(HEX_TARGETS) + +ifeq ($(shell netcat -z localhost 4000 && echo ok),ok) +hex-user-create: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Check that the user exists" + $t curl -sf http://localhost:4000/api/users/$(APP) >/dev/null + +# @todo Fix this. +#hex-user-create-password-with-dollar-sign: init +# +# $i "Bootstrap a new OTP application named $(APP)" +# $t mkdir $(APP)/ +# $t cp ../erlang.mk $(APP)/ +# $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v +# +# $i "Configure a local Hex provider" +# $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile +# +# $i "Create a Hex user" +# $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="123$$567" HEX_EMAIL=$(APP)@noone.nope $v +# +# $i "Check that the user exists" +# $t curl --user "$(APP):123$$567" -sf http://localhost:4000/api/users/$(APP) >/dev/null + +# @todo Fix this. +#hex-user-create-password-with-backslash: init +# +# $i "Bootstrap a new OTP application named $(APP)" +# $t mkdir $(APP)/ +# $t cp ../erlang.mk $(APP)/ +# $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v +# +# $i "Configure a local Hex provider" +# $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile +# +# $i "Create a Hex user" +# $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="123\\567" HEX_EMAIL=$(APP)@noone.nope $v +# +# $i "Check that the user exists" +# $t curl --user "$(APP):123\\567" -sf http://localhost:4000/api/users/$(APP) >/dev/null + +hex-user-create-password-with-space: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="123 567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Check that the user exists" + $t curl --user "$(APP):123 567" -sf http://localhost:4000/api/users/$(APP) >/dev/null + +hex-key-add: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" $v + + $i "Check that the key exists" + $t curl --user $(APP):1234567 -sf http://localhost:4000/api/keys/$(shell hostname)-erlang-mk >/dev/null + +hex-tarball-create: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Create a release tarball" + $t $(MAKE) -C $(APP) hex-tarball-create $v + + $i "Confirm the tarball contents can be extracted" + $t cd $(APP)/.erlang.mk/ && tar xf $(APP).tar + + $i "Confirm the tarball contains a CHECKSUM file" + $t test -f $(APP)/.erlang.mk/CHECKSUM + + $i "Confirm the tarball contains a VERSION file containing '3'" + $t cat $(APP)/.erlang.mk/VERSION | grep -q ^3$$ + + $i "Confirm the tarball contains a valid metadata.config file" + $t $(ERL) -eval " \ + {ok, _} = file:consult(\"$(APP)/.erlang.mk/metadata.config\"), \ + halt(0)" + + $i "Confirm the tarball contains a contents.tar.gz file that can be extracted" + $t cd $(APP)/.erlang.mk/ && tar xf contents.tar.gz + + $i "Confirm contents.tar.gz contains the expected files" + $t printf "%s\n" \ + erlang.mk \ + Makefile \ + ebin/$(APP).app \ + src/$(APP)_app.erl \ + src/$(APP)_sup.erl | sort > $(APP)/.erlang.mk/EXPECT + $t cd $(APP)/.erlang.mk/ && tar tf contents.tar.gz | sort | diff EXPECT - + +hex-tarball-create-with-deps: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Add Cowlib to the list of dependencies" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DEPS = cowlib\ndep_cowlib_commit = 2.10.1\n"}' $(APP)/Makefile + +ifdef LEGACY + $i "Add Cowlib to the applications key in the .app.src file" + $t perl -ni.bak -e 'print;if ($$.==7) {print "\t\tcowlib,\n"}' $(APP)/src/$(APP).app.src +endif + + $i "Create a release tarball" + $t $(MAKE) -C $(APP) hex-tarball-create $v + + $i "Confirm the tarball contents can be extracted" + $t cd $(APP)/.erlang.mk/ && tar xf $(APP).tar + + $i "Confirm the tarball contains a metadata.config file that lists Cowlib as requirement" + $t $(ERL) -eval " \ + {ok, Metadata} = file:consult(\"$(APP)/.erlang.mk/metadata.config\"), \ + {_, [{<<\"cowlib\">>, Cowlib}]} = lists:keyfind(<<\"requirements\">>, 1, Metadata), \ + {_, <<\"cowlib\">>} = lists:keyfind(<<\"app\">>, 1, Cowlib), \ + {_, false} = lists:keyfind(<<\"optional\">>, 1, Cowlib), \ + {_, <<\"2.10.1\">>} = lists:keyfind(<<\"requirement\">>, 1, Cowlib), \ + halt(0)" + +hex-release-publish: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Check that the release exists" + $t curl -sf http://localhost:4000/api/packages/$(APP)/releases/0.1.0 >/dev/null + +hex-release-publish-with-deps: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Add Cowlib to the list of dependencies" + $t perl -ni.bak -e 'print;if ($$.==1) {print "DEPS = cowlib\ndep_cowlib_commit = 2.10.1\n"}' $(APP)/Makefile + +ifdef LEGACY + $i "Add Cowlib to the applications key in the .app.src file" + $t perl -ni.bak -e 'print;if ($$.==7) {print "\t\tcowlib,\n"}' $(APP)/src/$(APP).app.src +endif + + $i "Build the application" + $t $(MAKE) -C $(APP) $v + + $i "Configure a local Hex provider for Cowlib" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/deps/cowlib/Makefile + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the Cowlib release" + $t $(MAKE) -C $(APP)/deps/cowlib hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Check that the release exists and includes Cowlib as requirement" + $t curl -sf http://localhost:4000/api/packages/$(APP)/releases/0.1.0 | grep -q cowlib + +hex-release-replace: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Update the project description" + $t sed -i.bak s/"PROJECT_DESCRIPTION = New project"/"PROJECT_DESCRIPTION = Best project"/ $(APP)/Makefile + + $i "Publish the release again, replacing the existing one" + $t $(MAKE) -C $(APP) hex-release-replace HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Check that the release was replaced" + $t curl -sf http://localhost:4000/api/packages/$(APP) | grep -q "Best project" + +hex-release-delete: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Delete the release" + $t $(MAKE) -C $(APP) hex-release-delete HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Check that the release was deleted" + $t ! curl -sf http://localhost:4000/api/packages/$(APP)/releases/0.1.0 >/dev/null + +hex-release-retire: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Retire the release" + $t $(MAKE) -C $(APP) hex-release-retire HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Check that the release was retired" + $t ! curl -sf http://localhost:4000/api/packages/$(APP)/releases/0.1.0 | grep -q \"retirement\":null + +hex-release-unretire: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Retire the release" + $t $(MAKE) -C $(APP) hex-release-retire HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Unretire the release" + $t $(MAKE) -C $(APP) hex-release-unretire HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Check that the release is no longer retired" + $t curl -sf http://localhost:4000/api/packages/$(APP)/releases/0.1.0 | grep -q \"retirement\":null + +hex-docs-tarball-create: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a doc/overview.edoc file" + $t mkdir $(APP)/doc + $t printf "%s\n" \ + "@author R. J. Hacker " \ + "@copyright 2007 R. J. Hacker" \ + "@version 1.0.0" \ + "@title Welcome to the 'frob' application!" \ + "@doc 'frob' is a highly advanced frobnicator with low latency," > $(APP)/doc/overview.edoc + + $i "Create a docs tarball" + $t $(MAKE) -C $(APP) hex-docs-tarball-create $v + + $i "Confirm the tarball contents can be extracted" + $t cd $(APP)/.erlang.mk/ && tar xf $(APP)-docs.tar.gz + + $i "Confirm the tarball contains the expected files" + $t printf "%s\n" \ + edoc-info \ + erlang.png \ + index.html \ + modules-frame.html \ + overview-summary.html \ + overview.edoc \ + stylesheet.css \ + $(APP)_app.html \ + $(APP)_sup.html | sort > $(APP)/.erlang.mk/EXPECT + $t cd $(APP)/.erlang.mk/ && tar tf $(APP)-docs.tar.gz | sort | diff EXPECT - + +hex-docs-publish: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a doc/overview.edoc file" + $t mkdir $(APP)/doc + $t printf "%s\n" \ + "@author R. J. Hacker " \ + "@copyright 2007 R. J. Hacker" \ + "@version 1.0.0" \ + "@title Welcome to the 'frob' application!" \ + "@doc 'frob' is a highly advanced frobnicator with low latency," > $(APP)/doc/overview.edoc + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Publish the documentation for the release" + $t $(MAKE) -C $(APP) hex-docs-publish HEX_SECRET=`cat $(APP)/hex.key` $v + +# @todo hex-docs-publish when there are no docs + +hex-docs-delete: init + + $i "Bootstrap a new OTP application named $(APP)" + $t mkdir $(APP)/ + $t cp ../erlang.mk $(APP)/ + $t $(MAKE) -C $(APP) -f erlang.mk bootstrap $v + + $i "Generate a doc/overview.edoc file" + $t mkdir $(APP)/doc + $t printf "%s\n" \ + "@author R. J. Hacker " \ + "@copyright 2007 R. J. Hacker" \ + "@version 1.0.0" \ + "@title Welcome to the 'frob' application!" \ + "@doc 'frob' is a highly advanced frobnicator with low latency," > $(APP)/doc/overview.edoc + + $i "Configure a local Hex provider" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_CONFIG\n#{api_url => <<\"http://localhost:4000/api\">>}\nendef\n"}' $(APP)/Makefile + + $i "Add extra Hex metadata" + $t perl -ni.bak -e 'print;if ($$.==1) {print "define HEX_TARBALL_EXTRA_METADATA\n#{licenses => [<<\"ISC\">>]}\nendef\n"}' $(APP)/Makefile + + $i "Create a Hex user" + $t $(MAKE) -C $(APP) hex-user-create HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" HEX_EMAIL=$(APP)@noone.nope $v + + $i "Create a key for that user" + $t $(MAKE) -C $(APP) hex-key-add HEX_USERNAME=$(APP) HEX_PASSWORD="1234567" | grep ^Secret: | cut -f2 -d" " > $(APP)/hex.key + + $i "Publish the release" + $t $(MAKE) -C $(APP) hex-release-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Publish the documentation for the release" + $t $(MAKE) -C $(APP) hex-docs-publish HEX_SECRET=`cat $(APP)/hex.key` $v + + $i "Delete the documentation for the release" + $t $(MAKE) -C $(APP) hex-docs-delete HEX_SECRET=`cat $(APP)/hex.key` $v +endif -- cgit v1.2.3