Compare commits

...

6 Commits

Author SHA1 Message Date
Jef Roosens 81ad9c35a4
feat(server): initial implementation of migrations
ci/woodpecker/pr/docs Pipeline was successful Details
ci/woodpecker/pr/lint Pipeline was successful Details
ci/woodpecker/pr/build Pipeline was successful Details
ci/woodpecker/pr/docker Pipeline was successful Details
ci/woodpecker/pr/test Pipeline was successful Details
2022-05-28 16:13:55 +02:00
Jef Roosens cdb88e1620 Merge pull request 'Add vieter schedule command' (#201) from Chewing_Bever/vieter:schedule-cli into dev
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/arch Pipeline was successful Details
ci/woodpecker/push/build Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details
ci/woodpecker/push/docker Pipeline was successful Details
ci/woodpecker/push/deploy Pipeline was successful Details
Reviewed-on: vieter/vieter#201
2022-05-26 13:50:11 +02:00
Jef Roosens 768da5b790
refactor: added CronExpression.next_n function
ci/woodpecker/pr/docs Pipeline was successful Details
ci/woodpecker/pr/lint Pipeline was successful Details
ci/woodpecker/pr/build Pipeline was successful Details
ci/woodpecker/pr/docker Pipeline was successful Details
ci/woodpecker/pr/test Pipeline was successful Details
2022-05-26 13:41:28 +02:00
Jef Roosens bd4bb9a9fb
feat: added cli command for previewing cron schedules 2022-05-26 09:15:49 +02:00
Jef Roosens c0b739035b Merge pull request 'fix(cron): retrieve all GitRepo's instead of first 25' (#198) from Chewing_Bever/vieter:cron-25-bug into dev
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/arch Pipeline was successful Details
ci/woodpecker/push/build Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details
ci/woodpecker/push/docker Pipeline was successful Details
ci/woodpecker/push/deploy Pipeline was successful Details
Reviewed-on: vieter/vieter#198
2022-05-25 09:36:08 +02:00
Jef Roosens 7f6e9e636c
fix(cron): retrieve all GitRepo's instead of first 25
ci/woodpecker/pr/docs Pipeline was successful Details
ci/woodpecker/pr/lint Pipeline was successful Details
ci/woodpecker/pr/build Pipeline was successful Details
ci/woodpecker/pr/docker Pipeline was successful Details
ci/woodpecker/pr/test Pipeline was successful Details
2022-05-25 09:24:01 +02:00
9 changed files with 146 additions and 6 deletions

View File

@ -4,7 +4,7 @@ import models { GitRepo, GitRepoFilter }
import net.http { Method } import net.http { Method }
import response { Response } import response { Response }
// get_git_repos returns the current list of repos. // get_git_repos returns a list of GitRepo's, given a filter object.
pub fn (c &Client) get_git_repos(filter GitRepoFilter) ?[]GitRepo { pub fn (c &Client) get_git_repos(filter GitRepoFilter) ?[]GitRepo {
params := models.params_from(filter) params := models.params_from(filter)
data := c.send_request<[]GitRepo>(Method.get, '/api/repos', params)? data := c.send_request<[]GitRepo>(Method.get, '/api/repos', params)?
@ -12,6 +12,27 @@ pub fn (c &Client) get_git_repos(filter GitRepoFilter) ?[]GitRepo {
return data.data 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. // get_git_repo returns the repo for a specific ID.
pub fn (c &Client) get_git_repo(id int) ?GitRepo { pub fn (c &Client) get_git_repo(id int) ?GitRepo {
data := c.send_request<GitRepo>(Method.get, '/api/repos/$id', {})? data := c.send_request<GitRepo>(Method.get, '/api/repos/$id', {})?

View File

@ -0,0 +1,30 @@
module schedule
import cli
import cron.expression { parse_expression }
import time
// cmd returns the cli submodule for previewing a cron schedule.
pub fn cmd() cli.Command {
return cli.Command{
name: 'schedule'
usage: 'schedule'
description: 'Preview the behavior of a cron schedule.'
flags: [
cli.Flag{
name: 'count'
description: 'How many scheduled times to show.'
flag: cli.FlagType.int
default_value: ['5']
},
]
execute: fn (cmd cli.Command) ? {
ce := parse_expression(cmd.args.join(' '))?
count := cmd.flags.get_int('count')?
for t in ce.next_n(time.now(), count)? {
println(t)
}
}
}
}

View File

@ -178,7 +178,7 @@ fn (mut d Daemon) schedule_build(repo GitRepo) {
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_git_repos() 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)

View File

@ -121,6 +121,20 @@ pub fn (ce &CronExpression) next_from_now() ?time.Time {
return ce.next(time.now()) return ce.next(time.now())
} }
// next_n returns the n next occurences of the expression, given a starting
// time.
pub fn (ce &CronExpression) next_n(ref time.Time, n int) ?[]time.Time {
mut times := []time.Time{cap: n}
times << ce.next(ref)?
for i in 1 .. n {
times << ce.next(times[i - 1])?
}
return times
}
// parse_range parses a given string into a range of sorted integers, if // parse_range parses a given string into a range of sorted integers, if
// possible. // possible.
fn parse_range(s string, min int, max int, mut bitv []bool) ? { fn parse_range(s string, min int, max int, mut bitv []bool) ? {

View File

@ -1,19 +1,65 @@
module db module db
import sqlite import sqlite
import models { BuildLog, GitRepo }
struct VieterDb { struct VieterDb {
conn sqlite.DB conn sqlite.DB
} }
struct MigrationVersion {
id int [primary]
version int
}
const (
migrations_up = [$embed_file('migrations/001-initial/up.sql')]
migrations_down = [$embed_file('migrations/001-initial/down.sql')]
)
// init initializes a database & adds the correct tables. // init initializes a database & adds the correct tables.
pub fn init(db_path string) ?VieterDb { pub fn init(db_path string) ?VieterDb {
conn := sqlite.connect(db_path)? conn := sqlite.connect(db_path)?
sql conn { sql conn {
create table GitRepo create table MigrationVersion
create table BuildLog }
cur_version := sql conn {
select from MigrationVersion limit 1
}
// If there's no row yet, we add it here
if cur_version == MigrationVersion{} {
sql conn {
insert cur_version into MigrationVersion
}
}
// Apply each migration in order
for i in cur_version.version .. db.migrations_up.len {
migration := db.migrations_up[i].to_string()
version_num := i + 1
// vfmt does not like these dots
println('Applying migration $version_num' + '...')
// The sqlite library seems to not like it when multiple statements are
// passed in a single exec. Therefore, we split them & run them all
// separately.
for part in migration.split(';').map(it.trim_space()).filter(it != '') {
res := conn.exec_none(part)
if res != sqlite.sqlite_done {
return error('An error occurred while applying migration $version_num')
}
}
// The where clause doesn't really matter, as there will always only be
// one entry anyways.
sql conn {
update MigrationVersion set version = version_num where id > 0
}
} }
return VieterDb{ return VieterDb{

View File

@ -0,0 +1,3 @@
DROP TABLE BuildLog;
DROP TABLE GitRepoArch;
DROP TABLE GitRepo;

View File

@ -0,0 +1,22 @@
CREATE TABLE IF NOT EXISTS GitRepo (
id INTEGER PRIMARY KEY,
url TEXT NOT NULL,
branch TEXT NOT NULL,
repo TEXT NOT NULL,
schedule TEXT
);
CREATE TABLE IF NOT EXISTS GitRepoArch (
id INTEGER PRIMARY KEY,
repo_id INTEGER NOT NULL,
value TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS BuildLog (
id INTEGER PRIMARY KEY,
repo_id INTEGER NOT NULL,
start_time INTEGER NOT NULL,
end_time iNTEGER NOT NULL,
arch TEXT NOT NULL,
exit_code INTEGER NOT NULL
);

View File

@ -5,6 +5,7 @@ import server
import cli import cli
import console.git import console.git
import console.logs import console.logs
import console.schedule
import cron import cron
fn main() { fn main() {
@ -27,6 +28,7 @@ fn main() {
git.cmd(), git.cmd(),
cron.cmd(), cron.cmd(),
logs.cmd(), logs.cmd(),
schedule.cmd(),
] ]
} }
app.setup() app.setup()

View File

@ -68,7 +68,9 @@ pub fn server(conf Config) ? {
} }
db_file := os.join_path_single(conf.data_dir, server.db_file_name) db_file := os.join_path_single(conf.data_dir, server.db_file_name)
db := db.init(db_file) or { util.exit_with_message(1, 'Failed to initialize database.') } db := db.init(db_file) or {
util.exit_with_message(1, 'Failed to initialize database: $err.msg()')
}
web.run(&App{ web.run(&App{
logger: logger logger: logger