<div align="center">

<img alt="Gitea" src="" width="240"/>

**`Elixir`** interface with a **`Gitea`** instance.

[![GitHub Workflow Status](](
[![ dependency status](](
[![contributions welcome](](

<!-- uncomment when service is working ...
[![Inline docs](](


# _Why?_ 💡

We needed an _easy_ way to interact
with a **`Gitea`** (GitHub Backup) **Server**
from our **`Elixir/Phoenix`** App.

> **Note**: We were _briefly_ tempted
> to write this code _inside_ the Phoenix App
> that uses it, <br />
> however we quickly realized
> that having it **_separate_** was better
> for **_testability/maintainability_**. <br />
> Having a _separate_ module enforces a
> [separation of concerns](
> with a strong "API contract". <br />
> This way we know this package is well-tested both end-to-end and with
> [Test Doubles](,
> documented and maintained. <br />
> It can be used and _extended independently_
> of any `Elixir/Phoenix` app
> and is treated
> as a logically separate/independent entity
> with a clear interface.

# _What_? 📦

A library for interacting with **`gitea`** (`git`)
from `Elixir` apps. <br />

Hopefully this diagram explains
how we use the package in our stack:

<div align="center">



For the complete list of functions,
please see the docs:

# Who? 👤

This library is used by our (`Phoenix`) GitHub Backup App. <br />
If you find it helpful for your project,
please ⭐ on GitHub:

## _How_? 💻

There are a couple of steps to get this working in your project.
It should only take **`2 mins`** if you already have your
**`Gitea` Server** _deployed_ (_or access to an existing instance_).

> If you want to read a **step-by-step complete beginner's guide**
> to getting **`gitea`** working in a **`Phoenix`** App,
> please see:
> [**gitea-demo**](

<br />

## Install ⬇️

Install the package from [](,
by adding `gitea` to the list of dependencies in your `mix.exs` file:

def deps do
    {:gitea, "~> 1.1.0"},

Once you've saved the `mix.exs` file,

mix deps.get

<br />

## Config ⚙️

If you are writing tests for a function that relies on `gitea` (and you should!)
then you can add the following line to your `config/test.exs` file:

config :gitea, mock: true

<br />

## _Setup_ 🔧

For `gitea` to work
in your `Elixir/Phoenix` App,
you will need to have
a few environment variables defined.

There are **2 _required_**
and **1 _optional_** variables.
Make sure you read through the next section
to determine if you _need_ the _optional_ ones.

### _Required_ Environment Variables

> See: [`.env_sample`](

There are **2 _required_** environment variables:

1. `GITEA_URL` - the domain where your Gitea Server is deployed,
   without the protocol, e.g: ``

2. `GITEA_ACCESS_TOKEN` - the REST API Access Token <br />

### _Optional_ Environment Variables


If you want to specify a directory where
you want to clone `git` repos to, <br />
create a `GIT_TEMP_DIR_PATH` environment variable.

export GIT_TEMP_DIR_PATH=tmp

> **Note**: the directory **must _already_ exist**.<br />
> If it doesn't already exist, create it. <br />
> e.g:
> `mkdir tmp` followed by `cp -r test-repo tmp`

<br />

## Usage

If you just want to _read_
the contents of a file hosted on
a `Gitea` Server,
write code similar to this:

org_name = "myorg"
repo_name = "public-repo"
file_name = ""
{:ok, %HTTPoison.Response{ body: response_body}} =
  Gitea.remote_read_raw(org_name, repo_name,file_name)
# use the response_body (plaintext data)

This is exactly the use-case presented in our demo app:

<br />

Here's a more real-world scenario
in 7 easy steps:

### 1. _Create_ a New Repo on the Gitea Server

# Define the params for the remote repository:
org_name = "myorg"
repo_name = "repo-name"
private = false # boolean
# Create the repo!
Gitea.remote_repo_create(org_name, repo_name, private)

### 2. _Clone_ the Repo

git_repo_url = Gitea.Helpers.remote_url_ssh(org_name, repo_name)

> Provided you have setup the environment variables,
> and your `Elixir/Phoenix` App has write access to the filesystem,
> this should work without any issues.
> We haven't seen any in practice.
> But if you get stuck at this step,
> [open an issue](

### 3. _Read_ the Contents of _Local_ (Cloned) File

Once you've cloned the `Git` Repo from the `Gitea` Server
to the local filesystem of the `Elixir/Phoenix` App,
you can read any file inside it.

org_name = "myorg"
repo_name = "public-repo"
file_name = ""
{:ok, text} = Gitea.local_file_read(org_name, repo_name, file_name)

### 4. _Write_ to a File

file_name = ""
text = "Your text"
Gitea.local_file_write_text(org_name, repo_name, file_name, text)

This will create a new file if it doesn't already exist.

### 5. _Commit_ Changes

{:ok, msg} = Gitea.commit(org_name, repo_name,
  %{message: "your commit message", full_name: "Al Ex", email: ""})

### 6. _Push_ to `Gitea` Remote

# Push to Gitea Server this one is easy.
Gitea.push(org_name, repo_name)

### 7. _Confirm_ the File was Update on the Remote repo

# Confirm the was updated on the remote repo:
{:ok, %HTTPoison.Response{ body: response_body}} =
    Gitea.remote_read_raw(org_name, repo_name, file_name)
"Your text"

<br />

## Full Function Reference / Docs? 📖

Rather than duplicate all the docs here,
please read the complete function reference,
on hexdocs:

<br />

## Tests!

By default, the tests run with "mocks",
this means that: <br />

1. Functional tests run faster (0.2 seconds)
2. Tests that require filesystem access will run on GitHub CI.
3. We know that functions are appropriately
   ["Test Doubled"]
   so that a downstream `Elixir/Phoenix` app
   can run in `mock: true` and tests will be mocked (and thus _fast_!)

To alter this setting to run the tests _without_ mocks,
simply change the boolean from:

config :gitea, mock: true


config :gitea, mock: false

You should still see the same output as all the functions should be tested.

### Test Coverage

When you run the command:

mix c

(an alias for `mix coveralls.html`) <br />
You will see output similar to the following:

Finished in 0.1 seconds (0.1s async, 0.00s sync)
3 doctests, 27 tests, 0 failures

Randomized with seed 715101
COV    FILE                                        LINES RELEVANT   MISSED
100.0% lib/git_mock.ex                                55        7        0
100.0% lib/gitea.ex                                   212       41        0
100.0% lib/helpers.ex                                131       17        0
100.0% lib/http.ex                                   119       18        0
100.0% lib/httpoison_mock.ex                         124       20        0
[TOTAL] 100.0%

If you want to run the tests _without_ mocks (i.e. "end-to-end"),
update the line in `config/test.exs`:

config :gitea, mock: false

When you run end-to-end tests with coverage tracking:

mix c

You should see the same output:

Finished in 5.5 seconds (5.5s async, 0.00s sync)
3 doctests, 27 tests, 0 failures

Randomized with seed 388372
COV    FILE                                        LINES RELEVANT   MISSED
100.0% lib/git_mock.ex                                55        7        0
100.0% lib/gitea.ex                                   212       41        0
100.0% lib/helpers.ex                                131       17        0
100.0% lib/http.ex                                   119       18        0
100.0% lib/httpoison_mock.ex                         124       20        0
[TOTAL] 100.0%

The only difference is the **_time_** it takes to run the test suite. <br />
The outcome (all tests passing and **100% coverage**) should be **_identical_**.

If you add a feature to the package,
please ensure that the tests pass
in both `mock: true` and `mock: false`
so that we know it works in the _real_ world
as well as in the simulated one.

<br />

## Roadmap

We are aiming to do a 1:1 feature map between GitHub and `Gitea`
so that we can backup our entire organisation, all repos, issues, labels & PRs.

We aren't there yet
and we might not be for some time.
The order in which we will be working
on fleshing out the features is:

1. **Git Diff** - using the `Git` module to determine the changes made to a specific file
   between two Git commits/hashes. This will allow us to visualize the changes made
   and can therefore _derive_ the contents of a Pull Request
   without having the PR feature exposed via the Gitea API.
2. **Issues**:

- **Comments** - this is the core content of issues.
  We need to parse all the data and map it to the fields in `Gitea`.
- **Labels** - the primary metadata we use to categorize our issues,
- **Milestones** - used to _group_ issues into batches, e.g. a "sprint" or "feature".

3. **Repo Stats**: Stars, watchers, forks etc.
4. **_Your_ Feature Request** Here!
   Seriously, if you spot a gap in the list of available functions,
   something you want/need to use `Gitea` in any a more advanced/custom way,
   please open an issue so we can discuss!

<br />

## I'm _Stuck!_ 🤷

As always, if anything is unclear
or you are stuck getting this working,
please open an issue!
we're here to help!

<br />

<br />

<hr />

# ⚠️ Disclaimer! ⚠️

This package is provided "**as is**".
We make **_no guarantee/warranty_** that it _works_. <br />
We _cannot_ be held responsible
for any undesirable effects of it's usage.
e.g: if you use the [`Gitea.delete/1`](
it will _permanently/irrecoverably_ **`delete`** the repo.
Use it with caution!

With the disclaimer out of the way,
and your expectations clearly set,
here are the facts:
We are using this package in "production".
We rely on it daily and consider it
["mission critical"](
It works for _us_ an and
we have made every effort to document,
test & _maintain_ it.
If you want to use it, go for it!
But please note that we cannot "_support_" your usage
beyond answering questions on GitHub.
And unless you have a commercial agreement with
[dwyl Ltd.]

If you spot anything that can be improved,
please open an
we're very happy to discuss!

[![feedback welcome](](