Skip to content

Commit 80b5525

Browse files
authored
Merge pull request #56 from Elixir-journey/refactor-post-start-to-mix-task
Replaced shell script by mix task for post start.
2 parents 0ed24cc + b074994 commit 80b5525

4 files changed

Lines changed: 188 additions & 76 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"context": ".."
66
},
77
"remoteEnv": {
8-
"MIX_ENV": "dev"
8+
"MIX_ENV": "dev",
9+
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}"
910
},
1011
"customizations": {
1112
"vscode": {
@@ -29,7 +30,7 @@
2930
}
3031
},
3132
"postCreateCommand": "mix deps.get",
32-
"postStartCommand": "/bin/sh /workspace/.devcontainer/scripts/post_start.sh",
33+
"postStartCommand": "mix post_start",
3334
"mounts": [
3435
"source=${localWorkspaceFolder},target=/workspace,type=bind",
3536
"source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached",

.devcontainer/scripts/post_start.sh

Lines changed: 0 additions & 74 deletions
This file was deleted.

lib/mix/tasks/post_start.ex

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
defmodule Mix.Tasks.PostStart do
2+
@shortdoc "Run post-start configuration"
3+
4+
@moduledoc false
5+
use Mix.Task
6+
7+
require Logger
8+
9+
def run(_args) do
10+
Logger.info("Starting post-start configuration...")
11+
12+
log_step("Loading environment variables", &load_environment_variables/0)
13+
log_step("Validating Git configuration", &validate_git_configuration/0)
14+
log_step("Configuring SSH", &configure_ssh/0)
15+
log_step("Setting up GitHub authentication", &setup_github_authentication/0)
16+
17+
Logger.info("Post-start configuration complete!")
18+
end
19+
20+
defp log_step(step_description, func) do
21+
Logger.info("Step: #{step_description}")
22+
23+
try do
24+
func.()
25+
rescue
26+
e -> Logger.error("#{step_description} failed: #{inspect(e)}")
27+
end
28+
end
29+
30+
defp load_environment_variables do
31+
if File.exists?(".env") do
32+
".env"
33+
|> File.read!()
34+
|> String.split("\n")
35+
|> Enum.reject(&String.starts_with?(&1, "#"))
36+
|> Enum.each(&load_env_var/1)
37+
38+
Logger.info("Environment variables loaded from .env")
39+
else
40+
Logger.info("No .env file found. Falling back to defaults.")
41+
end
42+
rescue
43+
e -> Logger.error("Failed to load environment variables: #{inspect(e)}")
44+
end
45+
46+
defp load_env_var(line) do
47+
trimmed_line = String.trim(line)
48+
49+
if trimmed_line == "" or String.starts_with?(trimmed_line, "#") do
50+
:ok
51+
else
52+
case String.split(trimmed_line, "=", parts: 2) do
53+
[key, value] -> System.put_env(key, value)
54+
_ -> Logger.error("Invalid .env line: #{line}")
55+
end
56+
end
57+
rescue
58+
e -> Logger.error("Error processing .env line: #{inspect(e)}")
59+
end
60+
61+
defp validate_git_configuration do
62+
Logger.info("Validating Git configuration...")
63+
64+
user_name = get_git_config("user.name") || "Unknown User"
65+
Logger.info("Git user.name: #{user_name}")
66+
67+
user_email = get_git_config("user.email") || "unknown@example.com"
68+
Logger.info("Git user.email: #{user_email}")
69+
rescue
70+
e -> Logger.error("Error validating Git configuration: #{inspect(e)}")
71+
end
72+
73+
defp get_git_config(key) do
74+
case System.cmd("git", ["config", "--global", key]) do
75+
{result, 0} -> String.trim(result)
76+
_ -> nil
77+
end
78+
rescue
79+
e ->
80+
Logger.error("Failed to retrieve Git config for #{key}: #{inspect(e)}")
81+
nil
82+
end
83+
84+
defp configure_ssh do
85+
Logger.info("Setting up SSH...")
86+
87+
System.cmd("ssh-agent", ["-s"])
88+
ssh_dir = Path.expand("~/.ssh")
89+
90+
if File.dir?(ssh_dir) do
91+
ssh_dir
92+
|> File.ls!()
93+
|> Enum.each(&set_ssh_key_permissions(&1, ssh_dir))
94+
95+
ssh_add("id_ed25519")
96+
ssh_add("id_rsa")
97+
else
98+
Logger.info("No SSH key found. Please ensure keys are available in ~/.ssh.")
99+
end
100+
101+
test_ssh_connection()
102+
rescue
103+
e -> Logger.error("Error setting up SSH: #{inspect(e)}")
104+
end
105+
106+
defp set_ssh_key_permissions(file, ssh_dir) do
107+
File.chmod!(Path.join(ssh_dir, file), 0o600)
108+
rescue
109+
e -> Logger.error("Error setting permissions for SSH key #{file}: #{inspect(e)}")
110+
end
111+
112+
defp ssh_add(key) do
113+
key_path = Path.expand("~/.ssh/#{key}")
114+
115+
if File.exists?(key_path) do
116+
System.cmd("ssh-add", [key_path])
117+
Logger.info("Added #{key} to SSH agent.")
118+
end
119+
rescue
120+
e -> Logger.error("Error adding SSH key #{key}: #{inspect(e)}")
121+
end
122+
123+
defp test_ssh_connection do
124+
Logger.info("Testing SSH connection to GitHub...")
125+
126+
case System.cmd("ssh", ["-T", "git@github.com"], stderr_to_stdout: true) do
127+
{output, 0} ->
128+
if String.contains?(output, "successfully authenticated") do
129+
Logger.info("#{output}")
130+
else
131+
Logger.error("SSH connection failed: #{output}")
132+
fallback_to_https()
133+
end
134+
135+
{error_output, _} ->
136+
Logger.error("SSH connection failed: #{error_output}")
137+
end
138+
rescue
139+
e -> Logger.error("Error testing SSH connection: #{inspect(e)}")
140+
end
141+
142+
defp fallback_to_https do
143+
case System.cmd("git", ["remote", "get-url", "origin"]) do
144+
{remote_url, 0} ->
145+
if String.starts_with?(remote_url, "git@github.com") do
146+
https_url = String.replace(remote_url, ~r/^git@github\.com:/, "https://github.com/")
147+
System.cmd("git", ["remote", "set-url", "origin", String.trim(https_url)])
148+
Logger.info("Updated remote URL to HTTPS: #{https_url}")
149+
else
150+
Logger.info("Remote URL does not use SSH. No changes made.")
151+
end
152+
153+
_ ->
154+
Logger.info("No remote URL to update.")
155+
end
156+
end
157+
158+
defp setup_github_authentication do
159+
Logger.info("Setting up GitHub authentication...")
160+
161+
if System.find_executable("gh") do
162+
github_token = System.get_env("GITHUB_TOKEN")
163+
164+
if github_token do
165+
authenticate_github_cli(github_token)
166+
else
167+
Logger.error("No GITHUB_TOKEN found in the environment. Please provide one in the .env file.")
168+
end
169+
else
170+
Logger.info("GitHub CLI not installed. Skipping authentication.")
171+
end
172+
end
173+
174+
defp authenticate_github_cli(github_token) do
175+
case System.cmd("gh", ["auth", "login", "--with-token"], env: [{"GITHUB_TOKEN", github_token}]) do
176+
{_result, 0} -> Logger.info("Authenticated with GitHub CLI.")
177+
_ -> Logger.error("GitHub CLI authentication failed.")
178+
end
179+
rescue
180+
e -> Logger.error("Error during GitHub CLI authentication: #{inspect(e)}")
181+
end
182+
end

mix.exs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ defmodule ElixirKickoff.MixProject do
1212
docs: [
1313
main: "readme",
1414
extras: ["README.md"]
15+
],
16+
dialyzer: [
17+
plt_add_apps: [:mix]
1518
]
1619
]
1720
end

0 commit comments

Comments
 (0)