Incorporate beachhead files from the previous mono-repo
This commit is contained in:
parent
50709621fd
commit
8b2f0102c4
36
.github/workflows/build.yml
vendored
Normal file
36
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Build and Publish Docker Container
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to Docker
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: git.joshuacoles.me
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and Push Docker image -- toggl-portal
|
||||
uses: docker/build-push-action@675965c0e16f1a0f94ecafff969d8c966f92c17b
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: git.joshuacoles.me/personal/beachhead-services/toggl-portal:arm
|
||||
build-args: |
|
||||
APP_NAME=toggl-portal
|
||||
PACKAGE_NAME=toggl-portal
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/target
|
||||
/.idea
|
||||
/ignore
|
||||
4009
Cargo.lock
generated
Normal file
4009
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,10 @@ name = "toggl-portal"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "toggl-portal"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
axum = { version = "0.6.20", features = ["multipart"] }
|
||||
@ -13,7 +17,6 @@ tower-http = { version = "0.4.3", features = ["trace", "cors", "compression-gzip
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json"] }
|
||||
anyhow = { version = "^1.0", features = ["backtrace"] }
|
||||
beachhead = { path = "../" }
|
||||
hyper = "0.14.27"
|
||||
reqwest = { version = "0.11.20", features = ["rustls", "json"] }
|
||||
base64 = "0.21.4"
|
||||
|
||||
88
Dockerfile
Normal file
88
Dockerfile
Normal file
@ -0,0 +1,88 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
################################################################################
|
||||
# Create a stage for building the application.
|
||||
|
||||
ARG RUST_VERSION=1.71.1
|
||||
ARG APP_NAME=timing-beachhead
|
||||
ARG PACKAGE_NAME=beachhead
|
||||
FROM rust:${RUST_VERSION}-slim-bullseye AS build
|
||||
ARG APP_NAME
|
||||
ARG PACKAGE_NAME
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
pkg-config \
|
||||
libssl-dev \
|
||||
&& \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Build the application.
|
||||
# Leverage a cache mount to /usr/local/cargo/registry/
|
||||
# for downloaded dependencies and a cache mount to /app/target/ for
|
||||
# compiled dependencies which will speed up subsequent builds.
|
||||
# Leverage a bind mount to the src directory to avoid having to copy the
|
||||
# source code into the container. Once built, copy the executable to an
|
||||
# output directory before the cache mounted /app/target is unmounted.
|
||||
RUN --mount=type=bind,source=src,target=src \
|
||||
--mount=type=bind,source=obsidian-portal,target=obsidian-portal \
|
||||
--mount=type=bind,source=toggl-portal,target=toggl-portal \
|
||||
--mount=type=bind,source=lectures-portal,target=lectures-portal \
|
||||
--mount=type=bind,source=Cargo.toml,target=Cargo.toml \
|
||||
--mount=type=bind,source=Cargo.lock,target=Cargo.lock \
|
||||
--mount=type=cache,target=/app/target/ \
|
||||
--mount=type=cache,target=/usr/local/cargo/registry/ \
|
||||
<<EOF
|
||||
set -e
|
||||
cargo build --locked --release --package $PACKAGE_NAME
|
||||
cp ./target/release/$APP_NAME /bin/server
|
||||
EOF
|
||||
|
||||
################################################################################
|
||||
# Create a new stage for running the application that contains the minimal
|
||||
# runtime dependencies for the application. This often uses a different base
|
||||
# image from the build stage where the necessary files are copied from the build
|
||||
# stage.
|
||||
#
|
||||
# The example below uses the debian bullseye image as the foundation for running the app.
|
||||
# By specifying the "bullseye-slim" tag, it will also use whatever happens to be the
|
||||
# most recent version of that tag when you build your Dockerfile. If
|
||||
# reproducability is important, consider using a digest
|
||||
# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
|
||||
FROM debian:bullseye-slim AS final
|
||||
|
||||
# Install curl for health check, clean up apt
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends ca-certificates curl && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Disabled to allow read access to the database file.
|
||||
## Create a non-privileged user that the app will run under.
|
||||
## See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
|
||||
#ARG UID=10001
|
||||
#RUN adduser \
|
||||
# --disabled-password \
|
||||
# --gecos "" \
|
||||
# --home "/nonexistent" \
|
||||
# --shell "/sbin/nologin" \
|
||||
# --no-create-home \
|
||||
# --uid "${UID}" \
|
||||
# appuser
|
||||
#USER appuser
|
||||
|
||||
# Copy the executable from the "build" stage.
|
||||
COPY --from=build /bin/server /bin/
|
||||
|
||||
# Expose the port that the application listens on.
|
||||
ENV ADDRESS=0.0.0.0:3000
|
||||
EXPOSE 3000
|
||||
|
||||
HEALTHCHECK \
|
||||
CMD curl -f http://localhost:3000/health || exit 1
|
||||
|
||||
# What the container should run when it is started.
|
||||
CMD ["/bin/server"]
|
||||
@ -12,7 +12,7 @@ use axum::routing::{get, post};
|
||||
use axum::{Extension, Json, Router};
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use base64::Engine;
|
||||
use beachhead::{shutdown_signal, Result};
|
||||
use utils::{shutdown_signal, Result};
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use clap::Parser;
|
||||
use migration::{Migrator, MigratorTrait};
|
||||
@ -30,6 +30,7 @@ mod db;
|
||||
mod entity;
|
||||
mod poll;
|
||||
mod types;
|
||||
mod utils;
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
struct Config {
|
||||
@ -202,7 +203,7 @@ fn from_csv_row(row: csv::StringRecord) -> ActiveModel {
|
||||
async fn import_csv(
|
||||
Extension(db): Extension<DatabaseConnection>,
|
||||
mut multipart: Multipart,
|
||||
) -> beachhead::Result<impl IntoResponse> {
|
||||
) -> Result<impl IntoResponse> {
|
||||
return Ok((StatusCode::NOT_IMPLEMENTED, "Not implemented"));
|
||||
|
||||
// while let Some(field) = multipart.next_field().await? {
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::entity::{client, project, time_entry};
|
||||
use crate::types::{Project, ProjectClient, TogglQuery};
|
||||
use sea_orm::{DatabaseConnection, EntityTrait, QuerySelect};
|
||||
use tracing::instrument;
|
||||
use crate::day_exclusivity_condition;
|
||||
use crate::{day_exclusivity_condition, utils};
|
||||
|
||||
#[tracing::instrument(skip(client, db))]
|
||||
pub async fn poll_job(client: TogglClient, db: DatabaseConnection, poll_period: u64) {
|
||||
@ -33,7 +33,7 @@ pub async fn poll_job(client: TogglClient, db: DatabaseConnection, poll_period:
|
||||
pub async fn perform_poll(
|
||||
client: &TogglClient,
|
||||
db: &DatabaseConnection,
|
||||
) -> beachhead::Result<usize> {
|
||||
) -> utils::Result<usize> {
|
||||
let now = chrono::Utc::now();
|
||||
let today_string = now
|
||||
.date_naive()
|
||||
|
||||
54
src/utils.rs
Normal file
54
src/utils.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::IntoResponse;
|
||||
use tokio::signal;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppError(anyhow::Error);
|
||||
|
||||
// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
|
||||
// `Result<_, AppError>`. That way you don't need to do that manually.
|
||||
impl<E> From<E> for AppError
|
||||
where
|
||||
E: Into<anyhow::Error>,
|
||||
{
|
||||
fn from(err: E) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
tracing::error!("{:?}", self);
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"An internal error occurred",
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T, E = AppError> = std::result::Result<T, E>;
|
||||
|
||||
pub async fn shutdown_signal() {
|
||||
let ctrl_c = async {
|
||||
signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to install Ctrl+C handler");
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
|
||||
#[cfg(not(unix))]
|
||||
let terminate = std::future::pending::<()>();
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user