Compare commits
	
		
			1 Commits 
		
	
	
		
			a8d647cca3
			...
			97d000f18f
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 97d000f18f | 
							
								
								
									
										10
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
								
								
								
								
							|  | @ -7,16 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||||||
| 
 | 
 | ||||||
| ## [Unreleased](https://git.rustybever.be/vieter/vieter/src/branch/dev) | ## [Unreleased](https://git.rustybever.be/vieter/vieter/src/branch/dev) | ||||||
| 
 | 
 | ||||||
| ### Added |  | ||||||
| 
 |  | ||||||
| * Server port can now be configured |  | ||||||
| 
 |  | ||||||
| ### Changed |  | ||||||
| 
 |  | ||||||
| * Moved all API routes under `/v1` namespace |  | ||||||
| * Renamed `vieter repos` to `vieter targets` |  | ||||||
| * Renamed `/api/v1/repos` namespace to `/api/v1/targets` |  | ||||||
| 
 |  | ||||||
| ### Removed | ### Removed | ||||||
| 
 | 
 | ||||||
| * md5 hashes are no longer calculated for packages | * md5 hashes are no longer calculated for packages | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| # Targets | # Git Repositories | ||||||
| 
 | 
 | ||||||
| <aside class="notice"> | <aside class="notice"> | ||||||
| 
 | 
 | ||||||
|  | @ -6,14 +6,15 @@ All routes in this section require authentication. | ||||||
| 
 | 
 | ||||||
| </aside> | </aside> | ||||||
| 
 | 
 | ||||||
| Endpoints for interacting with the list of targets stored on the server. | Endpoints for interacting with the list of Git repositories stored on the | ||||||
|  | server. | ||||||
| 
 | 
 | ||||||
| ## List targets | ## List repos | ||||||
| 
 | 
 | ||||||
| ```shell | ```shell | ||||||
| curl \ | curl \ | ||||||
|   -H 'X-Api-Key: secret' \ |   -H 'X-Api-Key: secret' \ | ||||||
|   https://example.com/api/v1/targets?offset=10&limit=20 |   https://example.com/api/repos?offset=10&limit=20 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| > JSON output format | > JSON output format | ||||||
|  | @ -31,7 +32,7 @@ curl \ | ||||||
|       "arch": [ |       "arch": [ | ||||||
|         { |         { | ||||||
|           "id": 1, |           "id": 1, | ||||||
|           "target_id": 1, |           "repo_id": 1, | ||||||
|           "value": "x86_64" |           "value": "x86_64" | ||||||
|         } |         } | ||||||
|       ] |       ] | ||||||
|  | @ -40,11 +41,11 @@ curl \ | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Retrieve a list of targets. | Retrieve a list of Git repositories. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `GET /api/v1/targets` | `GET /api/repos` | ||||||
| 
 | 
 | ||||||
| ### Query Parameters | ### Query Parameters | ||||||
| 
 | 
 | ||||||
|  | @ -52,14 +53,14 @@ Parameter | Description | ||||||
| --------- | ----------- | --------- | ----------- | ||||||
| limit | Maximum amount of results to return. | limit | Maximum amount of results to return. | ||||||
| offset | Offset of results. | offset | Offset of results. | ||||||
| repo | Limit results to targets that publish to the given repo. | repo | Limit results to repositories that publish to the given repo. | ||||||
| 
 | 
 | ||||||
| ## Get specific target | ## Get a repo | ||||||
| 
 | 
 | ||||||
| ```shell | ```shell | ||||||
| curl \ | curl \ | ||||||
|   -H 'X-Api-Key: secret' \ |   -H 'X-Api-Key: secret' \ | ||||||
|   https://example.com/api/v1/targets/1 |   https://example.com/api/repos/15 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| > JSON output format | > JSON output format | ||||||
|  | @ -76,7 +77,7 @@ curl \ | ||||||
|     "arch": [ |     "arch": [ | ||||||
|       { |       { | ||||||
|         "id": 1, |         "id": 1, | ||||||
|         "target_id": 1, |         "repo_id": 1, | ||||||
|         "value": "x86_64" |         "value": "x86_64" | ||||||
|       } |       } | ||||||
|     ] |     ] | ||||||
|  | @ -84,25 +85,25 @@ curl \ | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Get info about a specific target. | Get info about a specific Git repository. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `GET /api/v1/targets/:id` | `GET /api/repos/:id` | ||||||
| 
 | 
 | ||||||
| ### URL Parameters | ### URL Parameters | ||||||
| 
 | 
 | ||||||
| Parameter | Description | Parameter | Description | ||||||
| --------- | ----------- | --------- | ----------- | ||||||
| id | id of requested target | id | ID of requested repo | ||||||
| 
 | 
 | ||||||
| ## Create a new target | ## Create a new repo | ||||||
| 
 | 
 | ||||||
| Create a new target with the given data. | Create a new Git repository with the given data. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `POST /api/v1/targets` | `POST /api/repos` | ||||||
| 
 | 
 | ||||||
| ### Query Parameters | ### Query Parameters | ||||||
| 
 | 
 | ||||||
|  | @ -114,19 +115,19 @@ repo | Vieter repository to publish built packages to. | ||||||
| schedule | Cron build schedule (syntax explained [here](https://rustybever.be/docs/vieter/usage/builds/schedule/)) | schedule | Cron build schedule (syntax explained [here](https://rustybever.be/docs/vieter/usage/builds/schedule/)) | ||||||
| arch | Comma-separated list of architectures to build package on. | arch | Comma-separated list of architectures to build package on. | ||||||
| 
 | 
 | ||||||
| ## Modify a target | ## Modify a repo | ||||||
| 
 | 
 | ||||||
| Modify the data of an existing target. | Modify the data of an existing Git repository. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `PATCH /api/v1/targets/:id` | `PATCH /api/repos/:id` | ||||||
| 
 | 
 | ||||||
| ### URL Parameters | ### URL Parameters | ||||||
| 
 | 
 | ||||||
| Parameter | Description | Parameter | Description | ||||||
| --------- | ----------- | --------- | ----------- | ||||||
| id | id of target to modify | id | ID of requested repo | ||||||
| 
 | 
 | ||||||
| ### Query Parameters | ### Query Parameters | ||||||
| 
 | 
 | ||||||
|  | @ -138,16 +139,16 @@ repo | Vieter repository to publish built packages to. | ||||||
| schedule | Cron build schedule | schedule | Cron build schedule | ||||||
| arch | Comma-separated list of architectures to build package on. | arch | Comma-separated list of architectures to build package on. | ||||||
| 
 | 
 | ||||||
| ## Remove a target | ## Remove a repo | ||||||
| 
 | 
 | ||||||
| Remove a target from the server. | Remove a Git repository from the server. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `DELETE /api/v1/targets/:id` | `DELETE /api/repos/:id` | ||||||
| 
 | 
 | ||||||
| ### URL Parameters | ### URL Parameters | ||||||
| 
 | 
 | ||||||
| Parameter | Description | Parameter | Description | ||||||
| --------- | ----------- | --------- | ----------- | ||||||
| id | id of target to remove | id | ID of repo to remove | ||||||
|  | @ -13,7 +13,7 @@ Endpoints for interacting with stored build logs. | ||||||
| ```shell | ```shell | ||||||
| curl \ | curl \ | ||||||
|   -H 'X-Api-Key: secret' \ |   -H 'X-Api-Key: secret' \ | ||||||
|   https://example.com/api/v1/logs?offset=10&limit=20 |   https://example.com/api/logs?offset=10&limit=20 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| > JSON output format | > JSON output format | ||||||
|  | @ -24,7 +24,7 @@ curl \ | ||||||
|   "data": [ |   "data": [ | ||||||
|     { |     { | ||||||
|       "id": 1, |       "id": 1, | ||||||
|       "target_id": 3, |       "repo_id": 3, | ||||||
|       "start_time": 1652008554, |       "start_time": 1652008554, | ||||||
|       "end_time": 1652008559, |       "end_time": 1652008559, | ||||||
|       "arch": "x86_64", |       "arch": "x86_64", | ||||||
|  | @ -38,7 +38,7 @@ Retrieve a list of build logs. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `GET /api/v1/logs` | `GET /api/logs` | ||||||
| 
 | 
 | ||||||
| ### Query Parameters | ### Query Parameters | ||||||
| 
 | 
 | ||||||
|  | @ -46,7 +46,7 @@ Parameter | Description | ||||||
| --------- | ----------- | --------- | ----------- | ||||||
| limit | Maximum amount of results to return. | limit | Maximum amount of results to return. | ||||||
| offset | Offset of results. | offset | Offset of results. | ||||||
| target | Only return builds for this target id. | repo | Only return builds published to this repository. | ||||||
| before | Only return logs started before this time (UTC epoch) | before | Only return logs started before this time (UTC epoch) | ||||||
| after | Only return logs started after this time (UTC epoch) | after | Only return logs started after this time (UTC epoch) | ||||||
| arch | Only return logs built on this architecture | arch | Only return logs built on this architecture | ||||||
|  | @ -58,7 +58,7 @@ exit_codes | Comma-separated list of exit codes to limit result to; using `!` as | ||||||
| ```shell | ```shell | ||||||
| curl \ | curl \ | ||||||
|   -H 'X-Api-Key: secret' \ |   -H 'X-Api-Key: secret' \ | ||||||
|   https://example.com/api/v1/logs/1 |   https://example.com/api/logs/15 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| > JSON output format | > JSON output format | ||||||
|  | @ -68,7 +68,7 @@ curl \ | ||||||
|   "message": "", |   "message": "", | ||||||
|   "data": { |   "data": { | ||||||
|     "id": 1, |     "id": 1, | ||||||
|     "target_id": 3, |     "repo_id": 3, | ||||||
|     "start_time": 1652008554, |     "start_time": 1652008554, | ||||||
|     "end_time": 1652008559, |     "end_time": 1652008559, | ||||||
|     "arch": "x86_64", |     "arch": "x86_64", | ||||||
|  | @ -81,7 +81,7 @@ Retrieve info about a specific build log. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `GET /api/v1/logs/:id` | `GET /api/logs/:id` | ||||||
| 
 | 
 | ||||||
| ### URL Parameters | ### URL Parameters | ||||||
| 
 | 
 | ||||||
|  | @ -94,7 +94,7 @@ id | ID of requested log | ||||||
| ```shell | ```shell | ||||||
| curl \ | curl \ | ||||||
|   -H 'X-Api-Key: secret' \ |   -H 'X-Api-Key: secret' \ | ||||||
|   https://example.com/api/v1/logs/15/content |   https://example.com/api/logs/15/content | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Retrieve the contents of a build log. The response is the build log in | Retrieve the contents of a build log. The response is the build log in | ||||||
|  | @ -102,7 +102,7 @@ plaintext. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `GET /api/v1/logs/:id/content` | `GET /api/logs/:id/content` | ||||||
| 
 | 
 | ||||||
| ### URL Parameters | ### URL Parameters | ||||||
| 
 | 
 | ||||||
|  | @ -123,17 +123,17 @@ Publish a new build log to the server. | ||||||
| 
 | 
 | ||||||
| ### HTTP Request | ### HTTP Request | ||||||
| 
 | 
 | ||||||
| `POST /api/v1/logs` | `POST /api/logs` | ||||||
| 
 | 
 | ||||||
| ### Query parameters | ### Query parameters | ||||||
| 
 | 
 | ||||||
| Parameter | Description | Parameter | Description | ||||||
| --------- | ----------- | --------- | ----------- | ||||||
|  | id | ID of requested log | ||||||
| startTime | Start time of the build (UTC epoch) | startTime | Start time of the build (UTC epoch) | ||||||
| endTime | End time of the build (UTC epoch) | endTime | End time of the build (UTC epoch) | ||||||
| arch | Architecture on which the build was done | arch | Architecture on which the build was done | ||||||
| exitCode | Exit code of the build container | exitCode | Exit code of the build container | ||||||
| target | id of target this build is for |  | ||||||
| 
 | 
 | ||||||
| ### Request body | ### Request body | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ toc_footers: | ||||||
| 
 | 
 | ||||||
| includes: | includes: | ||||||
|   - repository |   - repository | ||||||
|   - targets |   - git | ||||||
|   - logs |   - logs | ||||||
| 
 | 
 | ||||||
| search: true | search: true | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ secrets file. | ||||||
| ## Commands | ## Commands | ||||||
| 
 | 
 | ||||||
| The first argument passed to Vieter determines which command you wish to use. | The first argument passed to Vieter determines which command you wish to use. | ||||||
| Each of these can contain subcommands (e.g. `vieter targets list`), but all | Each of these can contain subcommands (e.g. `vieter repos list`), but all | ||||||
| subcommands will use the same configuration. Below you can find the | subcommands will use the same configuration. Below you can find the | ||||||
| configuration variable required for each command. | configuration variable required for each command. | ||||||
| 
 | 
 | ||||||
|  | @ -45,8 +45,7 @@ configuration variable required for each command. | ||||||
|       This prevents the server from being confused when an `any` package is |       This prevents the server from being confused when an `any` package is | ||||||
|       published as the very first package for a repository. |       published as the very first package for a repository. | ||||||
|     * Git repositories added without an `arch` value use this value instead. |     * Git repositories added without an `arch` value use this value instead. | ||||||
| * `port`: HTTP port to run on | 
 | ||||||
|     * Default: `8000` |  | ||||||
| 
 | 
 | ||||||
| ### `vieter cron` | ### `vieter cron` | ||||||
| 
 | 
 | ||||||
|  | @ -89,11 +88,11 @@ configuration variable required for each command. | ||||||
| * `api_key`: the API key to use when authenticating requests. | * `api_key`: the API key to use when authenticating requests. | ||||||
| * `address`: Base URL of your Vieter instance, e.g. https://example.com | * `address`: Base URL of your Vieter instance, e.g. https://example.com | ||||||
| 
 | 
 | ||||||
| ### `vieter targets` | ### `vieter repos` | ||||||
| 
 | 
 | ||||||
| * `api_key`: the API key to use when authenticating requests. | * `api_key`: the API key to use when authenticating requests. | ||||||
| * `address`: Base URL of your Vieter instance, e.g. https://example.com | * `address`: Base URL of your Vieter instance, e.g. https://example.com | ||||||
| * `base_image`: image to use when building a package using `vieter targets | * `base_image`: image to use when building a package using `vieter repos | ||||||
|   build`. |   build`. | ||||||
|     * Default: `archlinux:base-devel` |     * Default: `archlinux:base-devel` | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -16,11 +16,11 @@ info to the system. The Vieter repository server exposes an HTTP API for this | ||||||
| info). For ease of use, the Vieter binary contains a CLI interface for | info). For ease of use, the Vieter binary contains a CLI interface for | ||||||
| interacting with this API (see [Configuration](/configuration) for | interacting with this API (see [Configuration](/configuration) for | ||||||
| configuration details). The [man | configuration details). The [man | ||||||
| pages](https://rustybever.be/man/vieter/vieter-targets.1.html) describe this in | pages](https://rustybever.be/man/vieter/vieter-repos.1.html) describe this in | ||||||
| greater detail, but the basic usage is as follows: | greater detail, but the basic usage is as follows: | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| vieter targets add some-url some-branch some-repository | vieter repos add some-url some-branch some-repository | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Here, `some-url` is the URL of the Git repository containing the PKGBUILD. This | Here, `some-url` is the URL of the Git repository containing the PKGBUILD. This | ||||||
|  | @ -37,7 +37,7 @@ should be published. | ||||||
| The above command intentionally leaves out a few parameters to make the CLI | The above command intentionally leaves out a few parameters to make the CLI | ||||||
| more useable. For information on how to modify all parameters using the CLI, | more useable. For information on how to modify all parameters using the CLI, | ||||||
| see | see | ||||||
| [vieter-targets-edit(1)](https://rustybever.be/man/vieter/vieter-targets-edit.1.html). | [vieter-repos-edit(1)](https://rustybever.be/man/vieter/vieter-repos-edit.1.html). | ||||||
| 
 | 
 | ||||||
| ## Reading logs | ## Reading logs | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ import time | ||||||
| import os | import os | ||||||
| import strings | import strings | ||||||
| import util | import util | ||||||
| import models { Target } | import models { GitRepo } | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	container_build_dir = '/build' | 	container_build_dir = '/build' | ||||||
|  | @ -91,9 +91,9 @@ pub: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // build_repo builds, packages & publishes a given Arch package based on the | // build_repo builds, packages & publishes a given Arch package based on the | ||||||
| // provided target. The base image ID should be of an image previously created | // provided GitRepo. The base image ID should be of an image previously created | ||||||
| // by create_build_image. It returns the logs of the container. | // by create_build_image. It returns the logs of the container. | ||||||
| pub fn build_repo(address string, api_key string, base_image_id string, repo &Target) ?BuildResult { | pub fn build_repo(address string, api_key string, base_image_id string, repo &GitRepo) ?BuildResult { | ||||||
| 	mut dd := docker.new_conn()? | 	mut dd := docker.new_conn()? | ||||||
| 
 | 
 | ||||||
| 	defer { | 	defer { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| module build | module build | ||||||
| 
 | 
 | ||||||
| import models { Target } | import models { GitRepo } | ||||||
| 
 | 
 | ||||||
| // escape_shell_string escapes any characters that could be interpreted | // escape_shell_string escapes any characters that could be interpreted | ||||||
| // incorrectly by a shell. The resulting value should be safe to use inside an | // incorrectly by a shell. The resulting value should be safe to use inside an | ||||||
|  | @ -22,8 +22,8 @@ pub fn echo_commands(cmds []string) []string { | ||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // create_build_script generates a shell script that builds a given Target. | // create_build_script generates a shell script that builds a given GitRepo. | ||||||
| fn create_build_script(address string, repo &Target, build_arch string) string { | fn create_build_script(address string, repo &GitRepo, build_arch string) string { | ||||||
| 	repo_url := '$address/$repo.repo' | 	repo_url := '$address/$repo.repo' | ||||||
| 
 | 
 | ||||||
| 	commands := echo_commands([ | 	commands := echo_commands([ | ||||||
|  |  | ||||||
|  | @ -1,15 +1,15 @@ | ||||||
| module build | module build | ||||||
| 
 | 
 | ||||||
| import models { Target } | import models { GitRepo } | ||||||
| 
 | 
 | ||||||
| fn test_create_build_script() { | fn test_create_build_script() { | ||||||
| 	target := Target{ | 	repo := GitRepo{ | ||||||
| 		id: 1 | 		id: 1 | ||||||
| 		url: 'https://examplerepo.com' | 		url: 'https://examplerepo.com' | ||||||
| 		branch: 'main' | 		branch: 'main' | ||||||
| 		repo: 'vieter' | 		repo: 'vieter' | ||||||
| 	} | 	} | ||||||
| 	build_script := create_build_script('https://example.com', target, 'x86_64') | 	build_script := create_build_script('https://example.com', repo, 'x86_64') | ||||||
| 	expected := $embed_file('build_script.sh') | 	expected := $embed_file('build_script.sh') | ||||||
| 
 | 
 | ||||||
| 	assert build_script == expected.to_string().trim_space() | 	assert build_script == expected.to_string().trim_space() | ||||||
|  |  | ||||||
|  | @ -0,0 +1,73 @@ | ||||||
|  | module client | ||||||
|  | 
 | ||||||
|  | import models { GitRepo, GitRepoFilter } | ||||||
|  | import net.http { Method } | ||||||
|  | import response { Response } | ||||||
|  | 
 | ||||||
|  | // get_git_repos returns a list of GitRepo's, given a filter object. | ||||||
|  | pub fn (c &Client) get_git_repos(filter GitRepoFilter) ?[]GitRepo { | ||||||
|  | 	params := models.params_from(filter) | ||||||
|  | 	data := c.send_request<[]GitRepo>(Method.get, '/api/repos', params)? | ||||||
|  | 
 | ||||||
|  | 	return data.data | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // get_all_git_repos retrieves *all* GitRepo's from the API using the default | ||||||
|  | // limit. | ||||||
|  | pub fn (c &Client) get_all_git_repos() ?[]GitRepo { | ||||||
|  | 	mut repos := []GitRepo{} | ||||||
|  | 	mut offset := u64(0) | ||||||
|  | 
 | ||||||
|  | 	for { | ||||||
|  | 		sub_repos := c.get_git_repos(offset: offset)? | ||||||
|  | 
 | ||||||
|  | 		if sub_repos.len == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		repos << sub_repos | ||||||
|  | 
 | ||||||
|  | 		offset += u64(sub_repos.len) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return repos | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // get_git_repo returns the repo for a specific ID. | ||||||
|  | pub fn (c &Client) get_git_repo(id int) ?GitRepo { | ||||||
|  | 	data := c.send_request<GitRepo>(Method.get, '/api/repos/$id', {})? | ||||||
|  | 
 | ||||||
|  | 	return data.data | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // add_git_repo adds a new repo to the server. | ||||||
|  | pub fn (c &Client) add_git_repo(url string, branch string, repo string, arch []string) ?Response<string> { | ||||||
|  | 	mut params := { | ||||||
|  | 		'url':    url | ||||||
|  | 		'branch': branch | ||||||
|  | 		'repo':   repo | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if arch.len > 0 { | ||||||
|  | 		params['arch'] = arch.join(',') | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	data := c.send_request<string>(Method.post, '/api/repos', params)? | ||||||
|  | 
 | ||||||
|  | 	return data | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // remove_git_repo removes the repo with the given ID from the server. | ||||||
|  | pub fn (c &Client) remove_git_repo(id int) ?Response<string> { | ||||||
|  | 	data := c.send_request<string>(Method.delete, '/api/repos/$id', {})? | ||||||
|  | 
 | ||||||
|  | 	return data | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // patch_git_repo sends a PATCH request to the given repo with the params as | ||||||
|  | // payload. | ||||||
|  | pub fn (c &Client) patch_git_repo(id int, params map[string]string) ?Response<string> { | ||||||
|  | 	data := c.send_request<string>(Method.patch, '/api/repos/$id', params)? | ||||||
|  | 
 | ||||||
|  | 	return data | ||||||
|  | } | ||||||
|  | @ -8,47 +8,47 @@ import time | ||||||
| // get_build_logs returns all build logs. | // get_build_logs returns all build logs. | ||||||
| pub fn (c &Client) get_build_logs(filter BuildLogFilter) ?Response<[]BuildLog> { | pub fn (c &Client) get_build_logs(filter BuildLogFilter) ?Response<[]BuildLog> { | ||||||
| 	params := models.params_from(filter) | 	params := models.params_from(filter) | ||||||
| 	data := c.send_request<[]BuildLog>(Method.get, '/api/v1/logs', params)? | 	data := c.send_request<[]BuildLog>(Method.get, '/api/logs', params)? | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // get_build_logs_for_target returns all build logs for a given target. | // get_build_logs_for_repo returns all build logs for a given repo. | ||||||
| pub fn (c &Client) get_build_logs_for_target(target_id int) ?Response<[]BuildLog> { | pub fn (c &Client) get_build_logs_for_repo(repo_id int) ?Response<[]BuildLog> { | ||||||
| 	params := { | 	params := { | ||||||
| 		'repo': target_id.str() | 		'repo': repo_id.str() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	data := c.send_request<[]BuildLog>(Method.get, '/api/v1/logs', params)? | 	data := c.send_request<[]BuildLog>(Method.get, '/api/logs', params)? | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // get_build_log returns a specific build log. | // get_build_log returns a specific build log. | ||||||
| pub fn (c &Client) get_build_log(id int) ?Response<BuildLog> { | pub fn (c &Client) get_build_log(id int) ?Response<BuildLog> { | ||||||
| 	data := c.send_request<BuildLog>(Method.get, '/api/v1/logs/$id', {})? | 	data := c.send_request<BuildLog>(Method.get, '/api/logs/$id', {})? | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // get_build_log_content returns the contents of the build log file. | // get_build_log_content returns the contents of the build log file. | ||||||
| pub fn (c &Client) get_build_log_content(id int) ?string { | pub fn (c &Client) get_build_log_content(id int) ?string { | ||||||
| 	data := c.send_request_raw_response(Method.get, '/api/v1/logs/$id/content', {}, '')? | 	data := c.send_request_raw_response(Method.get, '/api/logs/$id/content', {}, '')? | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // add_build_log adds a new build log to the server. | // add_build_log adds a new build log to the server. | ||||||
| pub fn (c &Client) add_build_log(target_id int, start_time time.Time, end_time time.Time, arch string, exit_code int, content string) ?Response<string> { | pub fn (c &Client) add_build_log(repo_id int, start_time time.Time, end_time time.Time, arch string, exit_code int, content string) ?Response<string> { | ||||||
| 	params := { | 	params := { | ||||||
| 		'target':    target_id.str() | 		'repo':      repo_id.str() | ||||||
| 		'startTime': start_time.unix_time().str() | 		'startTime': start_time.unix_time().str() | ||||||
| 		'endTime':   end_time.unix_time().str() | 		'endTime':   end_time.unix_time().str() | ||||||
| 		'arch':      arch | 		'arch':      arch | ||||||
| 		'exitCode':  exit_code.str() | 		'exitCode':  exit_code.str() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	data := c.send_request_with_body<string>(Method.post, '/api/v1/logs', params, content)? | 	data := c.send_request_with_body<string>(Method.post, '/api/logs', params, content)? | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,73 +0,0 @@ | ||||||
| module client |  | ||||||
| 
 |  | ||||||
| import models { Target, TargetFilter } |  | ||||||
| import net.http { Method } |  | ||||||
| import response { Response } |  | ||||||
| 
 |  | ||||||
| // get_targets returns a list of targets, given a filter object. |  | ||||||
| pub fn (c &Client) get_targets(filter TargetFilter) ?[]Target { |  | ||||||
| 	params := models.params_from(filter) |  | ||||||
| 	data := c.send_request<[]Target>(Method.get, '/api/v1/targets', params)? |  | ||||||
| 
 |  | ||||||
| 	return data.data |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // get_all_targets retrieves *all* targs from the API using the default |  | ||||||
| // limit. |  | ||||||
| pub fn (c &Client) get_all_targets() ?[]Target { |  | ||||||
| 	mut targets := []Target{} |  | ||||||
| 	mut offset := u64(0) |  | ||||||
| 
 |  | ||||||
| 	for { |  | ||||||
| 		sub_targets := c.get_targets(offset: offset)? |  | ||||||
| 
 |  | ||||||
| 		if sub_targets.len == 0 { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		targets << sub_targets |  | ||||||
| 
 |  | ||||||
| 		offset += u64(sub_targets.len) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return targets |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // get_target returns the target for a specific id. |  | ||||||
| pub fn (c &Client) get_target(id int) ?Target { |  | ||||||
| 	data := c.send_request<Target>(Method.get, '/api/v1/targets/$id', {})? |  | ||||||
| 
 |  | ||||||
| 	return data.data |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // add_target adds a new target to the server. |  | ||||||
| pub fn (c &Client) add_target(url string, branch string, repo string, arch []string) ?Response<string> { |  | ||||||
| 	mut params := { |  | ||||||
| 		'url':    url |  | ||||||
| 		'branch': branch |  | ||||||
| 		'repo':   repo |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if arch.len > 0 { |  | ||||||
| 		params['arch'] = arch.join(',') |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	data := c.send_request<string>(Method.post, '/api/v1/targets', params)? |  | ||||||
| 
 |  | ||||||
| 	return data |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // remove_target removes the target with the given id from the server. |  | ||||||
| pub fn (c &Client) remove_target(id int) ?Response<string> { |  | ||||||
| 	data := c.send_request<string>(Method.delete, '/api/v1/targets/$id', {})? |  | ||||||
| 
 |  | ||||||
| 	return data |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // patch_target sends a PATCH request to the given target with the params as |  | ||||||
| // payload. |  | ||||||
| pub fn (c &Client) patch_target(id int, params map[string]string) ?Response<string> { |  | ||||||
| 	data := c.send_request<string>(Method.patch, '/api/v1/targets/$id', params)? |  | ||||||
| 
 |  | ||||||
| 	return data |  | ||||||
| } |  | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| module targets | module git | ||||||
| 
 | 
 | ||||||
| import client | import client | ||||||
| import docker | import docker | ||||||
| import os | import os | ||||||
| import build | import build | ||||||
| 
 | 
 | ||||||
| // build locally builds the target with the given id. | // build builds every Git repo in the server's list. | ||||||
| fn build(conf Config, repo_id int) ? { | fn build(conf Config, repo_id int) ? { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf.address, conf.api_key) | ||||||
| 	repo := c.get_target(repo_id)? | 	repo := c.get_git_repo(repo_id)? | ||||||
| 
 | 
 | ||||||
| 	build_arch := os.uname().machine | 	build_arch := os.uname().machine | ||||||
| 
 | 
 | ||||||
|  | @ -1,11 +1,11 @@ | ||||||
| module targets | module git | ||||||
| 
 | 
 | ||||||
| import cli | import cli | ||||||
| import vieter.vconf | import vieter.vconf | ||||||
| import cron.expression { parse_expression } | import cron.expression { parse_expression } | ||||||
| import client | import client | ||||||
| import console | import console | ||||||
| import models { TargetFilter } | import models { GitRepoFilter } | ||||||
| 
 | 
 | ||||||
| struct Config { | struct Config { | ||||||
| 	address    string [required] | 	address    string [required] | ||||||
|  | @ -16,12 +16,12 @@ struct Config { | ||||||
| // cmd returns the cli submodule that handles the repos API interaction | // cmd returns the cli submodule that handles the repos API interaction | ||||||
| pub fn cmd() cli.Command { | pub fn cmd() cli.Command { | ||||||
| 	return cli.Command{ | 	return cli.Command{ | ||||||
| 		name: 'targets' | 		name: 'repos' | ||||||
| 		description: 'Interact with the targets API.' | 		description: 'Interact with the repos API.' | ||||||
| 		commands: [ | 		commands: [ | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
| 				name: 'list' | 				name: 'list' | ||||||
| 				description: 'List the current targets.' | 				description: 'List the current repos.' | ||||||
| 				flags: [ | 				flags: [ | ||||||
| 					cli.Flag{ | 					cli.Flag{ | ||||||
| 						name: 'limit' | 						name: 'limit' | ||||||
|  | @ -35,15 +35,15 @@ pub fn cmd() cli.Command { | ||||||
| 					}, | 					}, | ||||||
| 					cli.Flag{ | 					cli.Flag{ | ||||||
| 						name: 'repo' | 						name: 'repo' | ||||||
| 						description: 'Only return targets that publish to this repo.' | 						description: 'Only return Git repos that publish to this repo.' | ||||||
| 						flag: cli.FlagType.string | 						flag: cli.FlagType.string | ||||||
| 					}, | 					}, | ||||||
| 				] | 				] | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					mut filter := TargetFilter{} | 					mut filter := GitRepoFilter{} | ||||||
| 
 | 
 | ||||||
| 					limit := cmd.flags.get_int('limit')? | 					limit := cmd.flags.get_int('limit')? | ||||||
| 					if limit != 0 { | 					if limit != 0 { | ||||||
|  | @ -67,10 +67,10 @@ pub fn cmd() cli.Command { | ||||||
| 				name: 'add' | 				name: 'add' | ||||||
| 				required_args: 3 | 				required_args: 3 | ||||||
| 				usage: 'url branch repo' | 				usage: 'url branch repo' | ||||||
| 				description: 'Add a new Git repository target.' | 				description: 'Add a new repository.' | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					add(conf, cmd.args[0], cmd.args[1], cmd.args[2])? | 					add(conf, cmd.args[0], cmd.args[1], cmd.args[2])? | ||||||
| 				} | 				} | ||||||
|  | @ -79,10 +79,10 @@ pub fn cmd() cli.Command { | ||||||
| 				name: 'remove' | 				name: 'remove' | ||||||
| 				required_args: 1 | 				required_args: 1 | ||||||
| 				usage: 'id' | 				usage: 'id' | ||||||
| 				description: 'Remove a target that matches the given id.' | 				description: 'Remove a repository that matches the given ID prefix.' | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					remove(conf, cmd.args[0])? | 					remove(conf, cmd.args[0])? | ||||||
| 				} | 				} | ||||||
|  | @ -91,10 +91,10 @@ pub fn cmd() cli.Command { | ||||||
| 				name: 'info' | 				name: 'info' | ||||||
| 				required_args: 1 | 				required_args: 1 | ||||||
| 				usage: 'id' | 				usage: 'id' | ||||||
| 				description: 'Show detailed information for the target matching the id.' | 				description: 'Show detailed information for the repo matching the ID prefix.' | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					info(conf, cmd.args[0])? | 					info(conf, cmd.args[0])? | ||||||
| 				} | 				} | ||||||
|  | @ -103,7 +103,7 @@ pub fn cmd() cli.Command { | ||||||
| 				name: 'edit' | 				name: 'edit' | ||||||
| 				required_args: 1 | 				required_args: 1 | ||||||
| 				usage: 'id' | 				usage: 'id' | ||||||
| 				description: 'Edit the Git repository target that matches the given id.' | 				description: 'Edit the repository that matches the given ID prefix.' | ||||||
| 				flags: [ | 				flags: [ | ||||||
| 					cli.Flag{ | 					cli.Flag{ | ||||||
| 						name: 'url' | 						name: 'url' | ||||||
|  | @ -133,7 +133,7 @@ pub fn cmd() cli.Command { | ||||||
| 				] | 				] | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					found := cmd.flags.get_all_found() | 					found := cmd.flags.get_all_found() | ||||||
| 
 | 
 | ||||||
|  | @ -152,10 +152,10 @@ pub fn cmd() cli.Command { | ||||||
| 				name: 'build' | 				name: 'build' | ||||||
| 				required_args: 1 | 				required_args: 1 | ||||||
| 				usage: 'id' | 				usage: 'id' | ||||||
| 				description: 'Build the target with the given id & publish it.' | 				description: 'Build the repo with the given id & publish it.' | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					build(conf, cmd.args[0].int())? | 					build(conf, cmd.args[0].int())? | ||||||
| 				} | 				} | ||||||
|  | @ -168,9 +168,9 @@ pub fn cmd() cli.Command { | ||||||
| // ID. If multiple or none are found, an error is raised. | // ID. If multiple or none are found, an error is raised. | ||||||
| 
 | 
 | ||||||
| // list prints out a list of all repositories. | // list prints out a list of all repositories. | ||||||
| fn list(conf Config, filter TargetFilter) ? { | fn list(conf Config, filter GitRepoFilter) ? { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf.address, conf.api_key) | ||||||
| 	repos := c.get_targets(filter)? | 	repos := c.get_git_repos(filter)? | ||||||
| 	data := repos.map([it.id.str(), it.url, it.branch, it.repo]) | 	data := repos.map([it.id.str(), it.url, it.branch, it.repo]) | ||||||
| 
 | 
 | ||||||
| 	println(console.pretty_table(['id', 'url', 'branch', 'repo'], data)?) | 	println(console.pretty_table(['id', 'url', 'branch', 'repo'], data)?) | ||||||
|  | @ -179,7 +179,7 @@ fn list(conf Config, filter TargetFilter) ? { | ||||||
| // add adds a new repository to the server's list. | // add adds a new repository to the server's list. | ||||||
| fn add(conf Config, url string, branch string, repo string) ? { | fn add(conf Config, url string, branch string, repo string) ? { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf.address, conf.api_key) | ||||||
| 	res := c.add_target(url, branch, repo, [])? | 	res := c.add_git_repo(url, branch, repo, [])? | ||||||
| 
 | 
 | ||||||
| 	println(res.message) | 	println(res.message) | ||||||
| } | } | ||||||
|  | @ -191,7 +191,7 @@ fn remove(conf Config, id string) ? { | ||||||
| 
 | 
 | ||||||
| 	if id_int != 0 { | 	if id_int != 0 { | ||||||
| 		c := client.new(conf.address, conf.api_key) | 		c := client.new(conf.address, conf.api_key) | ||||||
| 		res := c.remove_target(id_int)? | 		res := c.remove_git_repo(id_int)? | ||||||
| 		println(res.message) | 		println(res.message) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -209,7 +209,7 @@ fn patch(conf Config, id string, params map[string]string) ? { | ||||||
| 	id_int := id.int() | 	id_int := id.int() | ||||||
| 	if id_int != 0 { | 	if id_int != 0 { | ||||||
| 		c := client.new(conf.address, conf.api_key) | 		c := client.new(conf.address, conf.api_key) | ||||||
| 		res := c.patch_target(id_int, params)? | 		res := c.patch_git_repo(id_int, params)? | ||||||
| 
 | 
 | ||||||
| 		println(res.message) | 		println(res.message) | ||||||
| 	} | 	} | ||||||
|  | @ -224,6 +224,6 @@ fn info(conf Config, id string) ? { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf.address, conf.api_key) | ||||||
| 	repo := c.get_target(id_int)? | 	repo := c.get_git_repo(id_int)? | ||||||
| 	println(repo) | 	println(repo) | ||||||
| } | } | ||||||
|  | @ -12,7 +12,7 @@ struct Config { | ||||||
| 	api_key string [required] | 	api_key string [required] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // cmd returns the cli module that handles the build logs API. | // cmd returns the cli module that handles the build repos API. | ||||||
| pub fn cmd() cli.Command { | pub fn cmd() cli.Command { | ||||||
| 	return cli.Command{ | 	return cli.Command{ | ||||||
| 		name: 'logs' | 		name: 'logs' | ||||||
|  | @ -33,8 +33,8 @@ pub fn cmd() cli.Command { | ||||||
| 						flag: cli.FlagType.int | 						flag: cli.FlagType.int | ||||||
| 					}, | 					}, | ||||||
| 					cli.Flag{ | 					cli.Flag{ | ||||||
| 						name: 'target' | 						name: 'repo' | ||||||
| 						description: 'Only return logs for this target id.' | 						description: 'Only return logs for this repo id.' | ||||||
| 						flag: cli.FlagType.int | 						flag: cli.FlagType.int | ||||||
| 					}, | 					}, | ||||||
| 					cli.Flag{ | 					cli.Flag{ | ||||||
|  | @ -65,7 +65,7 @@ pub fn cmd() cli.Command { | ||||||
| 				] | 				] | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					mut filter := BuildLogFilter{} | 					mut filter := BuildLogFilter{} | ||||||
| 
 | 
 | ||||||
|  | @ -79,9 +79,9 @@ pub fn cmd() cli.Command { | ||||||
| 						filter.offset = u64(offset) | 						filter.offset = u64(offset) | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					target_id := cmd.flags.get_int('target')? | 					repo_id := cmd.flags.get_int('repo')? | ||||||
| 					if target_id != 0 { | 					if repo_id != 0 { | ||||||
| 						filter.target = target_id | 						filter.repo = repo_id | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					tz_offset := time.offset() | 					tz_offset := time.offset() | ||||||
|  | @ -143,7 +143,7 @@ pub fn cmd() cli.Command { | ||||||
| 				description: 'Show all info for a specific build log.' | 				description: 'Show all info for a specific build log.' | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					id := cmd.args[0].int() | 					id := cmd.args[0].int() | ||||||
| 					info(conf, id)? | 					info(conf, id)? | ||||||
|  | @ -156,7 +156,7 @@ pub fn cmd() cli.Command { | ||||||
| 				description: 'Output the content of a build log to stdout.' | 				description: 'Output the content of a build log to stdout.' | ||||||
| 				execute: fn (cmd cli.Command) ? { | 				execute: fn (cmd cli.Command) ? { | ||||||
| 					config_file := cmd.flags.get_string('config-file')? | 					config_file := cmd.flags.get_string('config-file')? | ||||||
| 					conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 					conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 					id := cmd.args[0].int() | 					id := cmd.args[0].int() | ||||||
| 					content(conf, id)? | 					content(conf, id)? | ||||||
|  | @ -168,10 +168,10 @@ pub fn cmd() cli.Command { | ||||||
| 
 | 
 | ||||||
| // print_log_list prints a list of logs. | // print_log_list prints a list of logs. | ||||||
| fn print_log_list(logs []BuildLog) ? { | fn print_log_list(logs []BuildLog) ? { | ||||||
| 	data := logs.map([it.id.str(), it.target_id.str(), it.start_time.local().str(), | 	data := logs.map([it.id.str(), it.repo_id.str(), it.start_time.local().str(), | ||||||
| 		it.exit_code.str()]) | 		it.exit_code.str()]) | ||||||
| 
 | 
 | ||||||
| 	println(console.pretty_table(['id', 'target', 'start time', 'exit code'], data)?) | 	println(console.pretty_table(['id', 'repo', 'start time', 'exit code'], data)?) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // list prints a list of all build logs. | // list prints a list of all build logs. | ||||||
|  | @ -182,10 +182,10 @@ fn list(conf Config, filter BuildLogFilter) ? { | ||||||
| 	print_log_list(logs)? | 	print_log_list(logs)? | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // list prints a list of all build logs for a given target. | // list prints a list of all build logs for a given repo. | ||||||
| fn list_for_target(conf Config, target_id int) ? { | fn list_for_repo(conf Config, repo_id int) ? { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf.address, conf.api_key) | ||||||
| 	logs := c.get_build_logs_for_target(target_id)?.data | 	logs := c.get_build_logs_for_repo(repo_id)?.data | ||||||
| 
 | 
 | ||||||
| 	print_log_list(logs)? | 	print_log_list(logs)? | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ pub fn cmd() cli.Command { | ||||||
| 		description: 'Start the cron service that periodically runs builds.' | 		description: 'Start the cron service that periodically runs builds.' | ||||||
| 		execute: fn (cmd cli.Command) ? { | 		execute: fn (cmd cli.Command) ? { | ||||||
| 			config_file := cmd.flags.get_string('config-file')? | 			config_file := cmd.flags.get_string('config-file')? | ||||||
| 			conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 			conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 			cron(conf)? | 			cron(conf)? | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ import build | ||||||
| import docker | import docker | ||||||
| import os | import os | ||||||
| import client | import client | ||||||
| import models { Target } | import models { GitRepo } | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	// How many seconds to wait before retrying to update API if failed | 	// How many seconds to wait before retrying to update API if failed | ||||||
|  | @ -20,7 +20,7 @@ const ( | ||||||
| 
 | 
 | ||||||
| struct ScheduledBuild { | struct ScheduledBuild { | ||||||
| pub: | pub: | ||||||
| 	repo      Target | 	repo      GitRepo | ||||||
| 	timestamp time.Time | 	timestamp time.Time | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -38,7 +38,7 @@ mut: | ||||||
| 	api_update_frequency    int | 	api_update_frequency    int | ||||||
| 	image_rebuild_frequency int | 	image_rebuild_frequency int | ||||||
| 	// Repos currently loaded from API. | 	// Repos currently loaded from API. | ||||||
| 	repos []Target | 	repos []GitRepo | ||||||
| 	// At what point to update the list of repositories. | 	// At what point to update the list of repositories. | ||||||
| 	api_update_timestamp  time.Time | 	api_update_timestamp  time.Time | ||||||
| 	image_build_timestamp time.Time | 	image_build_timestamp time.Time | ||||||
|  | @ -149,7 +149,7 @@ pub fn (mut d Daemon) run() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // schedule_build adds the next occurence of the given repo build to the queue. | // schedule_build adds the next occurence of the given repo build to the queue. | ||||||
| fn (mut d Daemon) schedule_build(repo Target) { | fn (mut d Daemon) schedule_build(repo GitRepo) { | ||||||
| 	ce := if repo.schedule != '' { | 	ce := if repo.schedule != '' { | ||||||
| 		parse_expression(repo.schedule) or { | 		parse_expression(repo.schedule) or { | ||||||
| 			// TODO This shouldn't return an error if the expression is empty. | 			// TODO This shouldn't return an error if the expression is empty. | ||||||
|  | @ -178,7 +178,7 @@ fn (mut d Daemon) schedule_build(repo Target) { | ||||||
| fn (mut d Daemon) renew_repos() { | fn (mut d Daemon) renew_repos() { | ||||||
| 	d.linfo('Renewing repos...') | 	d.linfo('Renewing repos...') | ||||||
| 
 | 
 | ||||||
| 	mut new_repos := d.client.get_all_targets() or { | 	mut new_repos := d.client.get_all_git_repos() or { | ||||||
| 		d.lerror('Failed to renew repos. Retrying in ${daemon.api_update_retry_timeout}s...') | 		d.lerror('Failed to renew repos. Retrying in ${daemon.api_update_retry_timeout}s...') | ||||||
| 		d.api_update_timestamp = time.now().add_seconds(daemon.api_update_retry_timeout) | 		d.api_update_timestamp = time.now().add_seconds(daemon.api_update_retry_timeout) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,12 +13,8 @@ struct MigrationVersion { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	migrations_up   = [ | 	migrations_up   = [$embed_file('migrations/001-initial/up.sql')] | ||||||
| 		$embed_file('migrations/001-initial/up.sql'), | 	migrations_down = [$embed_file('migrations/001-initial/down.sql')] | ||||||
| 		$embed_file('migrations/002-rename-to-targets/up.sql'), |  | ||||||
| 	] |  | ||||||
| 	migrations_down = [$embed_file('migrations/001-initial/down.sql'), |  | ||||||
| 		$embed_file('migrations/002-rename-to-targets/down.sql')] |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // init initializes a database & adds the correct tables. | // init initializes a database & adds the correct tables. | ||||||
|  |  | ||||||
|  | @ -0,0 +1,99 @@ | ||||||
|  | module db | ||||||
|  | 
 | ||||||
|  | import models { GitRepo, GitRepoArch, GitRepoFilter } | ||||||
|  | 
 | ||||||
|  | // get_git_repos returns all GitRepo's in the database. | ||||||
|  | pub fn (db &VieterDb) get_git_repos(filter GitRepoFilter) []GitRepo { | ||||||
|  | 	// This seems to currently be blocked by a bug in the ORM, I'll have to ask | ||||||
|  | 	// around. | ||||||
|  | 	if filter.repo != '' { | ||||||
|  | 		res := sql db.conn { | ||||||
|  | 			select from GitRepo where repo == filter.repo order by id limit filter.limit offset filter.offset | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return res | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	res := sql db.conn { | ||||||
|  | 		select from GitRepo order by id limit filter.limit offset filter.offset | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // get_git_repo tries to return a specific GitRepo. | ||||||
|  | pub fn (db &VieterDb) get_git_repo(repo_id int) ?GitRepo { | ||||||
|  | 	res := sql db.conn { | ||||||
|  | 		select from GitRepo where id == repo_id | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// If a select statement fails, it returns a zeroed object. By | ||||||
|  | 	// checking one of the required fields, we can see whether the query | ||||||
|  | 	// returned a result or not. | ||||||
|  | 	if res.id == 0 { | ||||||
|  | 		return none | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // add_git_repo inserts the given GitRepo into the database. | ||||||
|  | pub fn (db &VieterDb) add_git_repo(repo GitRepo) { | ||||||
|  | 	sql db.conn { | ||||||
|  | 		insert repo into GitRepo | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // delete_git_repo deletes the repo with the given ID from the database. | ||||||
|  | pub fn (db &VieterDb) delete_git_repo(repo_id int) { | ||||||
|  | 	sql db.conn { | ||||||
|  | 		delete from GitRepo where id == repo_id | ||||||
|  | 		delete from GitRepoArch where repo_id == repo_id | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // update_git_repo updates any non-array values for a given GitRepo. | ||||||
|  | pub fn (db &VieterDb) update_git_repo(repo_id int, params map[string]string) { | ||||||
|  | 	mut values := []string{} | ||||||
|  | 
 | ||||||
|  | 	// TODO does this allow for SQL injection? | ||||||
|  | 	$for field in GitRepo.fields { | ||||||
|  | 		if field.name in params { | ||||||
|  | 			// Any fields that are array types require their own update method | ||||||
|  | 			$if field.typ is string { | ||||||
|  | 				values << "$field.name = '${params[field.name]}'" | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	values_str := values.join(', ') | ||||||
|  | 	// I think this is actual SQL & not the ORM language | ||||||
|  | 	query := 'update GitRepo set $values_str where id == $repo_id' | ||||||
|  | 
 | ||||||
|  | 	db.conn.exec_none(query) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // update_git_repo_archs updates a given GitRepo's arch value. | ||||||
|  | pub fn (db &VieterDb) update_git_repo_archs(repo_id int, archs []GitRepoArch) { | ||||||
|  | 	archs_with_id := archs.map(GitRepoArch{ | ||||||
|  | 		...it | ||||||
|  | 		repo_id: repo_id | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	sql db.conn { | ||||||
|  | 		delete from GitRepoArch where repo_id == repo_id | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for arch in archs_with_id { | ||||||
|  | 		sql db.conn { | ||||||
|  | 			insert arch into GitRepoArch | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // git_repo_exists is a utility function that checks whether a repo with the | ||||||
|  | // given id exists. | ||||||
|  | pub fn (db &VieterDb) git_repo_exists(repo_id int) bool { | ||||||
|  | 	db.get_git_repo(repo_id) or { return false } | ||||||
|  | 
 | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | @ -7,8 +7,8 @@ import time | ||||||
| pub fn (db &VieterDb) get_build_logs(filter BuildLogFilter) []BuildLog { | pub fn (db &VieterDb) get_build_logs(filter BuildLogFilter) []BuildLog { | ||||||
| 	mut where_parts := []string{} | 	mut where_parts := []string{} | ||||||
| 
 | 
 | ||||||
| 	if filter.target != 0 { | 	if filter.repo != 0 { | ||||||
| 		where_parts << 'target_id == $filter.target' | 		where_parts << 'repo_id == $filter.repo' | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if filter.before != time.Time{} { | 	if filter.before != time.Time{} { | ||||||
|  | @ -55,11 +55,11 @@ pub fn (db &VieterDb) get_build_logs(filter BuildLogFilter) []BuildLog { | ||||||
| 	return res | 	return res | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // get_build_logs_for_target returns all BuildLog's in the database for a given | // get_build_logs_for_repo returns all BuildLog's in the database for a given | ||||||
| // target. | // repo. | ||||||
| pub fn (db &VieterDb) get_build_logs_for_target(target_id int) []BuildLog { | pub fn (db &VieterDb) get_build_logs_for_repo(repo_id int) []BuildLog { | ||||||
| 	res := sql db.conn { | 	res := sql db.conn { | ||||||
| 		select from BuildLog where target_id == target_id order by id | 		select from BuildLog where repo_id == repo_id order by id | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return res | 	return res | ||||||
|  |  | ||||||
|  | @ -1,5 +0,0 @@ | ||||||
| ALTER TABLE Target RENAME TO GitRepo; |  | ||||||
| ALTER TABLE TargetArch RENAME TO GitRepoArch; |  | ||||||
| 
 |  | ||||||
| ALTER TABLE GitRepoArch RENAME COLUMN target_id TO repo_id; |  | ||||||
| ALTER TABLE BuildLog RENAME COLUMN target_id TO repo_id; |  | ||||||
|  | @ -1,5 +0,0 @@ | ||||||
| ALTER TABLE GitRepo RENAME TO Target; |  | ||||||
| ALTER TABLE GitRepoArch RENAME TO TargetArch; |  | ||||||
| 
 |  | ||||||
| ALTER TABLE TargetArch RENAME COLUMN repo_id TO target_id; |  | ||||||
| ALTER TABLE BuildLog RENAME COLUMN repo_id TO target_id; |  | ||||||
|  | @ -1,99 +0,0 @@ | ||||||
| module db |  | ||||||
| 
 |  | ||||||
| import models { Target, TargetArch, TargetFilter } |  | ||||||
| 
 |  | ||||||
| // get_targets returns all targets in the database. |  | ||||||
| pub fn (db &VieterDb) get_targets(filter TargetFilter) []Target { |  | ||||||
| 	// This seems to currently be blocked by a bug in the ORM, I'll have to ask |  | ||||||
| 	// around. |  | ||||||
| 	if filter.repo != '' { |  | ||||||
| 		res := sql db.conn { |  | ||||||
| 			select from Target where repo == filter.repo order by id limit filter.limit offset filter.offset |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return res |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	res := sql db.conn { |  | ||||||
| 		select from Target order by id limit filter.limit offset filter.offset |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return res |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // get_target tries to return a specific target. |  | ||||||
| pub fn (db &VieterDb) get_target(target_id int) ?Target { |  | ||||||
| 	res := sql db.conn { |  | ||||||
| 		select from Target where id == target_id |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// If a select statement fails, it returns a zeroed object. By |  | ||||||
| 	// checking one of the required fields, we can see whether the query |  | ||||||
| 	// returned a result or not. |  | ||||||
| 	if res.id == 0 { |  | ||||||
| 		return none |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return res |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // add_target inserts the given target into the database. |  | ||||||
| pub fn (db &VieterDb) add_target(repo Target) { |  | ||||||
| 	sql db.conn { |  | ||||||
| 		insert repo into Target |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // delete_target deletes the target with the given id from the database. |  | ||||||
| pub fn (db &VieterDb) delete_target(target_id int) { |  | ||||||
| 	sql db.conn { |  | ||||||
| 		delete from Target where id == target_id |  | ||||||
| 		delete from TargetArch where target_id == target_id |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // update_target updates any non-array values for a given target. |  | ||||||
| pub fn (db &VieterDb) update_target(target_id int, params map[string]string) { |  | ||||||
| 	mut values := []string{} |  | ||||||
| 
 |  | ||||||
| 	// TODO does this allow for SQL injection? |  | ||||||
| 	$for field in Target.fields { |  | ||||||
| 		if field.name in params { |  | ||||||
| 			// Any fields that are array types require their own update method |  | ||||||
| 			$if field.typ is string { |  | ||||||
| 				values << "$field.name = '${params[field.name]}'" |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	values_str := values.join(', ') |  | ||||||
| 	// I think this is actual SQL & not the ORM language |  | ||||||
| 	query := 'update Target set $values_str where id == $target_id' |  | ||||||
| 
 |  | ||||||
| 	db.conn.exec_none(query) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // update_target_archs updates a given target's arch value. |  | ||||||
| pub fn (db &VieterDb) update_target_archs(target_id int, archs []TargetArch) { |  | ||||||
| 	archs_with_id := archs.map(TargetArch{ |  | ||||||
| 		...it |  | ||||||
| 		target_id: target_id |  | ||||||
| 	}) |  | ||||||
| 
 |  | ||||||
| 	sql db.conn { |  | ||||||
| 		delete from TargetArch where target_id == target_id |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for arch in archs_with_id { |  | ||||||
| 		sql db.conn { |  | ||||||
| 			insert arch into TargetArch |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // target_exists is a utility function that checks whether a target with the |  | ||||||
| // given id exists. |  | ||||||
| pub fn (db &VieterDb) target_exists(target_id int) bool { |  | ||||||
| 	db.get_target(target_id) or { return false } |  | ||||||
| 
 |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  | @ -3,7 +3,7 @@ module main | ||||||
| import os | import os | ||||||
| import server | import server | ||||||
| import cli | import cli | ||||||
| import console.targets | import console.git | ||||||
| import console.logs | import console.logs | ||||||
| import console.schedule | import console.schedule | ||||||
| import console.man | import console.man | ||||||
|  | @ -26,7 +26,7 @@ fn main() { | ||||||
| 		] | 		] | ||||||
| 		commands: [ | 		commands: [ | ||||||
| 			server.cmd(), | 			server.cmd(), | ||||||
| 			targets.cmd(), | 			git.cmd(), | ||||||
| 			cron.cmd(), | 			cron.cmd(), | ||||||
| 			logs.cmd(), | 			logs.cmd(), | ||||||
| 			schedule.cmd(), | 			schedule.cmd(), | ||||||
|  |  | ||||||
|  | @ -1,18 +1,18 @@ | ||||||
| module models | module models | ||||||
| 
 | 
 | ||||||
| pub struct TargetArch { | pub struct GitRepoArch { | ||||||
| pub: | pub: | ||||||
| 	id        int    [primary; sql: serial] | 	id      int    [primary; sql: serial] | ||||||
| 	target_id int    [nonull] | 	repo_id int    [nonull] | ||||||
| 	value     string [nonull] | 	value   string [nonull] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // str returns a string representation. | // str returns a string representation. | ||||||
| pub fn (gra &TargetArch) str() string { | pub fn (gra &GitRepoArch) str() string { | ||||||
| 	return gra.value | 	return gra.value | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct Target { | pub struct GitRepo { | ||||||
| pub mut: | pub mut: | ||||||
| 	id int [primary; sql: serial] | 	id int [primary; sql: serial] | ||||||
| 	// URL of the Git repository | 	// URL of the Git repository | ||||||
|  | @ -25,11 +25,11 @@ pub mut: | ||||||
| 	schedule string | 	schedule string | ||||||
| 	// On which architectures the package is allowed to be built. In reality, | 	// On which architectures the package is allowed to be built. In reality, | ||||||
| 	// this controls which builders will periodically build the image. | 	// this controls which builders will periodically build the image. | ||||||
| 	arch []TargetArch [fkey: 'target_id'] | 	arch []GitRepoArch [fkey: 'repo_id'] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // str returns a string representation. | // str returns a string representation. | ||||||
| pub fn (gr &Target) str() string { | pub fn (gr &GitRepo) str() string { | ||||||
| 	mut parts := [ | 	mut parts := [ | ||||||
| 		'id: $gr.id', | 		'id: $gr.id', | ||||||
| 		'url: $gr.url', | 		'url: $gr.url', | ||||||
|  | @ -44,7 +44,7 @@ pub fn (gr &Target) str() string { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [params] | [params] | ||||||
| pub struct TargetFilter { | pub struct GitRepoFilter { | ||||||
| pub mut: | pub mut: | ||||||
| 	limit  u64 = 25 | 	limit  u64 = 25 | ||||||
| 	offset u64 | 	offset u64 | ||||||
|  | @ -5,7 +5,7 @@ import time | ||||||
| pub struct BuildLog { | pub struct BuildLog { | ||||||
| pub mut: | pub mut: | ||||||
| 	id         int       [primary; sql: serial] | 	id         int       [primary; sql: serial] | ||||||
| 	target_id  int       [nonull] | 	repo_id    int       [nonull] | ||||||
| 	start_time time.Time [nonull] | 	start_time time.Time [nonull] | ||||||
| 	end_time   time.Time [nonull] | 	end_time   time.Time [nonull] | ||||||
| 	arch       string    [nonull] | 	arch       string    [nonull] | ||||||
|  | @ -16,7 +16,7 @@ pub mut: | ||||||
| pub fn (bl &BuildLog) str() string { | pub fn (bl &BuildLog) str() string { | ||||||
| 	mut parts := [ | 	mut parts := [ | ||||||
| 		'id: $bl.id', | 		'id: $bl.id', | ||||||
| 		'target id: $bl.target_id', | 		'repo id: $bl.repo_id', | ||||||
| 		'start time: $bl.start_time.local()', | 		'start time: $bl.start_time.local()', | ||||||
| 		'end time: $bl.end_time.local()', | 		'end time: $bl.end_time.local()', | ||||||
| 		'duration: ${bl.end_time - bl.start_time}', | 		'duration: ${bl.end_time - bl.start_time}', | ||||||
|  | @ -33,7 +33,7 @@ pub struct BuildLogFilter { | ||||||
| pub mut: | pub mut: | ||||||
| 	limit      u64 = 25 | 	limit      u64 = 25 | ||||||
| 	offset     u64 | 	offset     u64 | ||||||
| 	target     int | 	repo       int | ||||||
| 	before     time.Time | 	before     time.Time | ||||||
| 	after      time.Time | 	after      time.Time | ||||||
| 	arch       string | 	arch       string | ||||||
|  |  | ||||||
|  | @ -23,8 +23,8 @@ pub fn patch_from_params<T>(mut o T, params map[string]string) ? { | ||||||
| 				o.$(field.name) = params[field.name].int() | 				o.$(field.name) = params[field.name].int() | ||||||
| 			} $else $if field.typ is u64 { | 			} $else $if field.typ is u64 { | ||||||
| 				o.$(field.name) = params[field.name].u64() | 				o.$(field.name) = params[field.name].u64() | ||||||
| 			} $else $if field.typ is []TargetArch { | 			} $else $if field.typ is []GitRepoArch { | ||||||
| 				o.$(field.name) = params[field.name].split(',').map(TargetArch{ value: it }) | 				o.$(field.name) = params[field.name].split(',').map(GitRepoArch{ value: it }) | ||||||
| 			} $else $if field.typ is time.Time { | 			} $else $if field.typ is time.Time { | ||||||
| 				o.$(field.name) = time.unix(params[field.name].int()) | 				o.$(field.name) = time.unix(params[field.name].int()) | ||||||
| 			} $else $if field.typ is []string { | 			} $else $if field.typ is []string { | ||||||
|  |  | ||||||
|  | @ -1,6 +0,0 @@ | ||||||
| This module contains the Vieter HTTP server, consisting of the repository |  | ||||||
| implementation & the REST API. |  | ||||||
| 
 |  | ||||||
| **NOTE**: vweb defines the priority order of routes by the file names in this |  | ||||||
| module. Therefore, it's very important that all API routes are defined in files |  | ||||||
| prefixed with `api_`, as this is before the word `routes` alphabetically. |  | ||||||
|  | @ -10,7 +10,6 @@ pub: | ||||||
| 	data_dir     string | 	data_dir     string | ||||||
| 	api_key      string | 	api_key      string | ||||||
| 	default_arch string | 	default_arch string | ||||||
| 	port         int = 8000 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // cmd returns the cli submodule that handles starting the server | // cmd returns the cli submodule that handles starting the server | ||||||
|  | @ -20,7 +19,7 @@ pub fn cmd() cli.Command { | ||||||
| 		description: 'Start the Vieter server.' | 		description: 'Start the Vieter server.' | ||||||
| 		execute: fn (cmd cli.Command) ? { | 		execute: fn (cmd cli.Command) ? { | ||||||
| 			config_file := cmd.flags.get_string('config-file')? | 			config_file := cmd.flags.get_string('config-file')? | ||||||
| 			conf := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)? | 			conf := vconf.load<Config>(default_path: config_file)? | ||||||
| 
 | 
 | ||||||
| 			server(conf)? | 			server(conf)? | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -4,38 +4,38 @@ import web | ||||||
| import net.http | import net.http | ||||||
| import response { new_data_response, new_response } | import response { new_data_response, new_response } | ||||||
| import db | import db | ||||||
| import models { Target, TargetArch, TargetFilter } | import models { GitRepo, GitRepoArch, GitRepoFilter } | ||||||
| 
 | 
 | ||||||
| // v1_get_targets returns the current list of targets. | // get_repos returns the current list of repos. | ||||||
| ['/api/v1/targets'; get] | ['/api/repos'; get] | ||||||
| fn (mut app App) v1_get_targets() web.Result { | fn (mut app App) get_repos() web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	filter := models.from_params<TargetFilter>(app.query) or { | 	filter := models.from_params<GitRepoFilter>(app.query) or { | ||||||
| 		return app.json(http.Status.bad_request, new_response('Invalid query parameters.')) | 		return app.json(http.Status.bad_request, new_response('Invalid query parameters.')) | ||||||
| 	} | 	} | ||||||
| 	repos := app.db.get_targets(filter) | 	repos := app.db.get_git_repos(filter) | ||||||
| 
 | 
 | ||||||
| 	return app.json(http.Status.ok, new_data_response(repos)) | 	return app.json(http.Status.ok, new_data_response(repos)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // v1_get_single_target returns the information for a single target. | // get_single_repo returns the information for a single repo. | ||||||
| ['/api/v1/targets/:id'; get] | ['/api/repos/:id'; get] | ||||||
| fn (mut app App) v1_get_single_target(id int) web.Result { | fn (mut app App) get_single_repo(id int) web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	repo := app.db.get_target(id) or { return app.not_found() } | 	repo := app.db.get_git_repo(id) or { return app.not_found() } | ||||||
| 
 | 
 | ||||||
| 	return app.json(http.Status.ok, new_data_response(repo)) | 	return app.json(http.Status.ok, new_data_response(repo)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // v1_post_target creates a new target from the provided query string. | // post_repo creates a new repo from the provided query string. | ||||||
| ['/api/v1/targets'; post] | ['/api/repos'; post] | ||||||
| fn (mut app App) v1_post_target() web.Result { | fn (mut app App) post_repo() web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
|  | @ -48,40 +48,40 @@ fn (mut app App) v1_post_target() web.Result { | ||||||
| 		params['arch'] = app.conf.default_arch | 		params['arch'] = app.conf.default_arch | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	new_repo := models.from_params<Target>(params) or { | 	new_repo := models.from_params<GitRepo>(params) or { | ||||||
| 		return app.json(http.Status.bad_request, new_response(err.msg())) | 		return app.json(http.Status.bad_request, new_response(err.msg())) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	app.db.add_target(new_repo) | 	app.db.add_git_repo(new_repo) | ||||||
| 
 | 
 | ||||||
| 	return app.json(http.Status.ok, new_response('Repo added successfully.')) | 	return app.json(http.Status.ok, new_response('Repo added successfully.')) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // v1_delete_target removes a given target from the server's list. | // delete_repo removes a given repo from the server's list. | ||||||
| ['/api/v1/targets/:id'; delete] | ['/api/repos/:id'; delete] | ||||||
| fn (mut app App) v1_delete_target(id int) web.Result { | fn (mut app App) delete_repo(id int) web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	app.db.delete_target(id) | 	app.db.delete_git_repo(id) | ||||||
| 
 | 
 | ||||||
| 	return app.json(http.Status.ok, new_response('Repo removed successfully.')) | 	return app.json(http.Status.ok, new_response('Repo removed successfully.')) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // v1_patch_target updates a target's data with the given query params. | // patch_repo updates a repo's data with the given query params. | ||||||
| ['/api/v1/targets/:id'; patch] | ['/api/repos/:id'; patch] | ||||||
| fn (mut app App) v1_patch_target(id int) web.Result { | fn (mut app App) patch_repo(id int) web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	app.db.update_target(id, app.query) | 	app.db.update_git_repo(id, app.query) | ||||||
| 
 | 
 | ||||||
| 	if 'arch' in app.query { | 	if 'arch' in app.query { | ||||||
| 		arch_objs := app.query['arch'].split(',').map(TargetArch{ value: it }) | 		arch_objs := app.query['arch'].split(',').map(GitRepoArch{ value: it }) | ||||||
| 
 | 
 | ||||||
| 		app.db.update_target_archs(id, arch_objs) | 		app.db.update_git_repo_archs(id, arch_objs) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return app.json(http.Status.ok, new_response('Repo updated successfully.')) | 	return app.json(http.Status.ok, new_response('Repo updated successfully.')) | ||||||
|  | @ -10,10 +10,10 @@ import os | ||||||
| import util | import util | ||||||
| import models { BuildLog, BuildLogFilter } | import models { BuildLog, BuildLogFilter } | ||||||
| 
 | 
 | ||||||
| // v1_get_logs returns all build logs in the database. A 'target' query param can | // get_logs returns all build logs in the database. A 'repo' query param can | ||||||
| // optionally be added to limit the list of build logs to that repository. | // optionally be added to limit the list of build logs to that repository. | ||||||
| ['/api/v1/logs'; get] | ['/api/logs'; get] | ||||||
| fn (mut app App) v1_get_logs() web.Result { | fn (mut app App) get_logs() web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
|  | @ -26,9 +26,9 @@ fn (mut app App) v1_get_logs() web.Result { | ||||||
| 	return app.json(http.Status.ok, new_data_response(logs)) | 	return app.json(http.Status.ok, new_data_response(logs)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // v1_get_single_log returns the build log with the given id. | // get_single_log returns the build log with the given id. | ||||||
| ['/api/v1/logs/:id'; get] | ['/api/logs/:id'; get] | ||||||
| fn (mut app App) v1_get_single_log(id int) web.Result { | fn (mut app App) get_single_log(id int) web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
|  | @ -38,16 +38,16 @@ fn (mut app App) v1_get_single_log(id int) web.Result { | ||||||
| 	return app.json(http.Status.ok, new_data_response(log)) | 	return app.json(http.Status.ok, new_data_response(log)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // v1_get_log_content returns the actual build log file for the given id. | // get_log_content returns the actual build log file for the given id. | ||||||
| ['/api/v1/logs/:id/content'; get] | ['/api/logs/:id/content'; get] | ||||||
| fn (mut app App) v1_get_log_content(id int) web.Result { | fn (mut app App) get_log_content(id int) web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	log := app.db.get_build_log(id) or { return app.not_found() } | 	log := app.db.get_build_log(id) or { return app.not_found() } | ||||||
| 	file_name := log.start_time.custom_format('YYYY-MM-DD_HH-mm-ss') | 	file_name := log.start_time.custom_format('YYYY-MM-DD_HH-mm-ss') | ||||||
| 	full_path := os.join_path(app.conf.data_dir, logs_dir_name, log.target_id.str(), log.arch, | 	full_path := os.join_path(app.conf.data_dir, logs_dir_name, log.repo_id.str(), log.arch, | ||||||
| 		file_name) | 		file_name) | ||||||
| 
 | 
 | ||||||
| 	return app.file(full_path) | 	return app.file(full_path) | ||||||
|  | @ -62,9 +62,9 @@ fn parse_query_time(query string) ?time.Time { | ||||||
| 	return t | 	return t | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // v1_post_log adds a new log to the database. | // post_log adds a new log to the database. | ||||||
| ['/api/v1/logs'; post] | ['/api/logs'; post] | ||||||
| fn (mut app App) v1_post_log() web.Result { | fn (mut app App) post_log() web.Result { | ||||||
| 	if !app.is_authorized() { | 	if !app.is_authorized() { | ||||||
| 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | 		return app.json(http.Status.unauthorized, new_response('Unauthorized.')) | ||||||
| 	} | 	} | ||||||
|  | @ -96,15 +96,15 @@ fn (mut app App) v1_post_log() web.Result { | ||||||
| 
 | 
 | ||||||
| 	arch := app.query['arch'] | 	arch := app.query['arch'] | ||||||
| 
 | 
 | ||||||
| 	target_id := app.query['target'].int() | 	repo_id := app.query['repo'].int() | ||||||
| 
 | 
 | ||||||
| 	if !app.db.target_exists(target_id) { | 	if !app.db.git_repo_exists(repo_id) { | ||||||
| 		return app.json(http.Status.bad_request, new_response('Unknown target.')) | 		return app.json(http.Status.bad_request, new_response('Unknown Git repo.')) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Store log in db | 	// Store log in db | ||||||
| 	log := BuildLog{ | 	log := BuildLog{ | ||||||
| 		target_id: target_id | 		repo_id: repo_id | ||||||
| 		start_time: start_time | 		start_time: start_time | ||||||
| 		end_time: end_time | 		end_time: end_time | ||||||
| 		arch: arch | 		arch: arch | ||||||
|  | @ -113,7 +113,7 @@ fn (mut app App) v1_post_log() web.Result { | ||||||
| 
 | 
 | ||||||
| 	app.db.add_build_log(log) | 	app.db.add_build_log(log) | ||||||
| 
 | 
 | ||||||
| 	repo_logs_dir := os.join_path(app.conf.data_dir, logs_dir_name, target_id.str(), arch) | 	repo_logs_dir := os.join_path(app.conf.data_dir, logs_dir_name, repo_id.str(), arch) | ||||||
| 
 | 
 | ||||||
| 	// Create the logs directory of it doesn't exist | 	// Create the logs directory of it doesn't exist | ||||||
| 	if !os.exists(repo_logs_dir) { | 	if !os.exists(repo_logs_dir) { | ||||||
|  | @ -8,6 +8,7 @@ import util | ||||||
| import db | import db | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
|  | 	port          = 8000 | ||||||
| 	log_file_name = 'vieter.log' | 	log_file_name = 'vieter.log' | ||||||
| 	repo_dir_name = 'repos' | 	repo_dir_name = 'repos' | ||||||
| 	db_file_name  = 'vieter.sqlite' | 	db_file_name  = 'vieter.sqlite' | ||||||
|  | @ -76,5 +77,5 @@ pub fn server(conf Config) ? { | ||||||
| 		conf: conf | 		conf: conf | ||||||
| 		repo: repo | 		repo: repo | ||||||
| 		db: db | 		db: db | ||||||
| 	}, conf.port) | 	}, server.port) | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue