Skip to content

Commit aec0992

Browse files
committed
Add write function
1 parent 57a8d7f commit aec0992

File tree

2 files changed

+81
-6
lines changed

2 files changed

+81
-6
lines changed

src/git_store.gleam

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import gleam/http/response
66
import gleam/httpc
77
import gleam/io
88
import gleam/json
9+
import gleam/option.{type Option, None, Some}
910
import gleam/result
1011
import gleam/string
1112

@@ -28,11 +29,21 @@ pub type GitHubResponse {
2829
GitHubFileResponse(content: String, encoding: String, sha: String, size: Int)
2930
}
3031

32+
/// The required fields to create a new file in a GitHub repo.
33+
/// Message is the commit message
34+
/// Content is the base64 encoded text content of the file
35+
pub type GitHubFile {
36+
GitHubFile(message: String, content: String)
37+
}
38+
3139
pub fn repos_url(config: GitHubConfig) -> String {
3240
config.base_url <> "/repos"
3341
}
3442

35-
pub fn read_file(
43+
/// Get a file object from a GitHub repository at the given path
44+
/// Path should be a '/' separated String, e.g:
45+
/// 'foo/bar/baz'
46+
pub fn get_file(
3647
config: GitHubConfig,
3748
path: String,
3849
) -> Result(response.Response(String), GitStoreError) {
@@ -46,10 +57,15 @@ pub fn read_file(
4657
<> "/"
4758
<> path
4859

49-
request(config, http.Get, url)
60+
request(config, http.Get, url, None)
5061
}
5162

52-
fn request(config: GitHubConfig, method: http.Method, endpoint: String) {
63+
fn request(
64+
config: GitHubConfig,
65+
method: http.Method,
66+
endpoint: String,
67+
json_body: Option(String),
68+
) {
5369
use req <- result.try(
5470
request.to(endpoint)
5571
|> result.map_error(fn(_) {
@@ -62,6 +78,7 @@ fn request(config: GitHubConfig, method: http.Method, endpoint: String) {
6278
|> request.set_header("Authorization", "Bearer " <> config.token)
6379
|> request.set_header("Accept", "application/vnd.github+json")
6480
|> request.set_header("User-Agent", "GitStore-Gleam")
81+
|> utils.set_json(json_body)
6582
|> request.set_method(method)
6683
|> httpc.send()
6784

@@ -72,18 +89,30 @@ fn request(config: GitHubConfig, method: http.Method, endpoint: String) {
7289
})
7390
}
7491

92+
/// Parse the JSON data from file.body, converting the base64 encoded content
93+
/// into a String
7594
fn file_from_json(
7695
json_string: String,
7796
) -> Result(GitHubResponse, json.DecodeError) {
97+
logging.log(logging.Debug, json_string)
7898
let file_decoder = {
7999
use content <- decode.field(
80100
"content",
81101
decode.then(decode.string, fn(item) {
82102
let decoded =
83-
item |> bit_array.base64_decode |> result.try(bit_array.to_string)
103+
item
104+
|> string.replace("\n", "")
105+
|> bit_array.base64_decode
106+
|> result.try(bit_array.to_string)
84107
case decoded {
85108
Ok(str) -> decode.success(str)
86-
Error(_) -> decode.failure("", "A base64 encoded String")
109+
Error(_) -> {
110+
logging.log(
111+
logging.Error,
112+
"Failed to decode expected base64 string: " <> item,
113+
)
114+
decode.failure("", "A base64 encoded String")
115+
}
87116
}
88117
}),
89118
)
@@ -95,15 +124,47 @@ fn file_from_json(
95124
json.parse(json_string, using: file_decoder)
96125
}
97126

127+
fn file_to_json(file: GitHubFile) -> String {
128+
json.object([
129+
#("message", json.string(file.message)),
130+
#("content", json.string(file.content)),
131+
])
132+
|> json.to_string
133+
}
134+
135+
fn create_file(config: GitHubConfig, filename: String, content: String) {
136+
let url =
137+
utils.build_path(config.base_url, [
138+
"repos",
139+
config.owner,
140+
config.repo,
141+
"contents",
142+
])
143+
<> "/"
144+
<> filename
145+
let content =
146+
content
147+
|> bit_array.from_string
148+
|> bit_array.base64_encode(True)
149+
let file = GitHubFile("add: " <> filename, content:)
150+
let res = request(config, http.Put, url, Some(file |> file_to_json))
151+
logging.log(logging.Debug, "Writing file: " <> string.inspect(res))
152+
}
153+
98154
pub fn main() -> Nil {
99155
logging.configure()
156+
logging.set_level(logging.Debug)
100157
let owner = envoy.get("GITHUB_OWNER") |> result.unwrap("")
101158
let repo = envoy.get("GITHUB_REPO") |> result.unwrap("")
102159
let token = envoy.get("GITHUB_TOKEN") |> result.unwrap("")
103160
let base_url =
104161
envoy.get("GITHUB_BASE_URL") |> result.unwrap("https://api.github.com")
105162
let config = GithubConfig(owner, repo, token, base_url)
106-
let file = read_file(config, "README.md") |> result.unwrap(response.new(400))
163+
logging.log(logging.Debug, config |> string.inspect)
164+
let file = get_file(config, "README.md") |> result.unwrap(response.new(400))
165+
echo file_from_json(file.body)
166+
let new_file = create_file(config, "test", "foo bar baz")
167+
let file = get_file(config, "test") |> result.unwrap(response.new(400))
107168
echo file_from_json(file.body)
108169
io.println("Hello from git_store!")
109170
}

src/git_store/utils.gleam

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
1+
import gleam/http/request
12
import gleam/list
3+
import gleam/option.{type Option, None, Some}
24

35
pub fn build_path(base: String, segments: List(String)) -> String {
46
segments
57
|> list.fold(base, fn(path, segment) { path <> "/" <> segment })
68
}
9+
10+
/// Set the JSON content type header and JSON body if json_body is not None
11+
pub fn set_json(req: request.Request(String), json_body: Option(String)) {
12+
case json_body {
13+
Some(body) ->
14+
req
15+
|> request.set_header("Content-Type", "application/json")
16+
|> request.set_body(body)
17+
18+
None -> req
19+
}
20+
}

0 commit comments

Comments
 (0)