commit 59571f752d007f5d0022b72691dcf3384f0b3378
parent 5052eb6f373da9e75eafac3b444a55ce3abda400
Author: arjoonn <arjoonn@noreply.localhost>
Date: Sun, 19 Feb 2023 08:31:33 +0000
Report to multiple remotes and add email remote (!43)
Branch auto created by JayporeCI
```jayporeci
╔ 🟢 : JayporeCI [sha 14729bffa0]
┏━ build_and_test
┃
┃ 🟢 : JciEnv [631400de] 5:51
┃ 🟢 : Jci [39817329] 0:15 ❮-- ['JciEnv']
┃ 🟢 : black [bff952d0] 0: 0 ❮-- ['JciEnv']
┃ 🟢 : pylint [df90af0b] 0: 5 ❮-- ['JciEnv']
┃ 🟢 : pytest [9d144b4e] 0: 1 71% ❮-- ['JciEnv']
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Publish
┃
┃ 🟢 : DockerHubJci [83a0a4ab] 2: 2
┃ 🟢 : DockerHubJcienv [94df1826] 2: 7
┃ 🟢 : PublishDocs [7cec4420] 0:32
┃ 🟢 : PublishPypi [e40c3cf6] 0: 6
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
```
Co-authored-by: arjoonn sharma <arjoonn@midpathsoftware.com>
Reviewed-on: https://gitea.midpathsoftware.com/midpath/jaypore_ci/pulls/43
Diffstat:
16 files changed, 347 insertions(+), 149 deletions(-)
diff --git a/cicd/cicd.py b/cicd/cicd.py
@@ -1,13 +1,12 @@
from jaypore_ci import jci
-
with jci.Pipeline() as p:
- jcienv = f"jcienv:{p.remote.sha}"
+ jcienv = f"jcienv:{p.repo.sha}"
with p.stage("build_and_test"):
- p.job("JciEnv", f"docker build --target jcienv -t jcienv:{p.remote.sha} .")
+ p.job("JciEnv", f"docker build --target jcienv -t jcienv:{p.repo.sha} .")
p.job(
"Jci",
- f"docker build --target jci -t jci:{p.remote.sha} .",
+ f"docker build --target jci -t jci:{p.repo.sha} .",
depends_on=["JciEnv"],
)
kwargs = dict(image=jcienv, depends_on=["JciEnv"])
diff --git a/docs/source/index.rst b/docs/source/index.rst
@@ -190,7 +190,7 @@ codebase, then builds and publishes documentation.
from jaypore_ci import jci
with jci.Pipeline() as p:
- image = f"myproject_{p.remote.sha}"
+ image = f"myproject_{p.repo.sha}"
with p.stage("build"):
p.job("DockDev", f"docker build --target DevEnv -t {image}_dev .")
@@ -216,16 +216,16 @@ codebase, then builds and publishes documentation.
)
with p.stage("publish"):
- p.job("TagProd", f"docker tag -t {image}_prod hub/{image}_prod:{p.remote.sha}")
- p.job("TagDev", f"docker tag -t {image}_dev hub/{image}_dev:{p.remote.sha}")
+ p.job("TagProd", f"docker tag -t {image}_prod hub/{image}_prod:{p.repo.sha}")
+ p.job("TagDev", f"docker tag -t {image}_dev hub/{image}_dev:{p.repo.sha}")
p.job(
"PushProd",
- f"docker push hub/{image}_prod:{p.remote.sha}",
+ f"docker push hub/{image}_prod:{p.repo.sha}",
depends_on=["TagProd"],
)
p.job(
"PushDev",
- f"docker push hub/{image}_dev:{p.remote.sha}",
+ f"docker push hub/{image}_dev:{p.repo.sha}",
depends_on=["TagDev"],
)
p.job(
@@ -339,7 +339,7 @@ different jobs.
with jci.Pipeline() as p:
p.job("testing", "bash cicd/lint_test_n_build.sh")
- if p.remote.branch == 'main':
+ if p.repo.branch == 'main':
p.job("publish", "bash cicd/publish_release.sh", depends_on=['testing'])
@@ -373,6 +373,24 @@ would test and make sure that jobs are running in order.
order = pipeline.executor.get_execution_order()
assert order["x"] < order["y"] < order["z"]
+Status report via email
+-----------------------
+
+You can send pipeline status reports via email if you don't want to use the PR system for gitea/github etc.
+
+See the :class:`~jaypore_ci.remotes.email.Email` docs for the environment
+variables you will have to supply to make this work.
+
+.. code-block:: python
+
+ from jaypore_ci import jci, executors, remotes, repos
+
+ git = repos.Git.from_env()
+ email = remotes.Email.from_env(repo=git)
+
+ with jci.Pipeline(repo=git, remote=email) as p:
+ p.job("x", "x")
+
Contributing
============
diff --git a/jaypore_ci/interfaces.py b/jaypore_ci/interfaces.py
@@ -5,7 +5,7 @@ Currently only gitea and docker are supported as remote and executor
respectively.
"""
from enum import Enum
-from typing import NamedTuple
+from typing import NamedTuple, List
class TriggerFailed(Exception):
@@ -34,6 +34,29 @@ class Status(Enum):
SKIPPED = 70
+class Repo:
+ """
+ Contains information about the current VCS repo.
+ """
+
+ def __init__(self, sha: str, branch: str, remote: str):
+ self.sha: str = sha
+ self.branch: str = branch
+ self.remote: str = remote
+
+ def files_changed(self, target: str) -> List[str]:
+ "Returns list of files changed between current sha and target"
+ raise NotImplementedError()
+
+ @classmethod
+ def from_env(cls) -> "Repo":
+ """
+ Creates a :class:`~jaypore_ci.interfaces.Repo` instance
+ from the environment and git repo on disk.
+ """
+ raise NotImplementedError()
+
+
class Executor:
"""
An executor is something used to run a job.
@@ -97,7 +120,7 @@ class Remote:
pass
@classmethod
- def from_env(cls):
+ def from_env(cls, *, repo: "Repo"):
"""
This function should create a Remote instance from the given environment.
It can read git information / look at environment variables etc.
diff --git a/jaypore_ci/jci.py b/jaypore_ci/jci.py
@@ -12,8 +12,15 @@ from contextlib import contextmanager
import structlog
import pendulum
-from jaypore_ci import remotes, executors, reporters
-from jaypore_ci.interfaces import Remote, Executor, Reporter, TriggerFailed, Status
+from jaypore_ci import remotes, executors, reporters, repos
+from jaypore_ci.interfaces import (
+ Remote,
+ Executor,
+ Reporter,
+ TriggerFailed,
+ Status,
+ Repo,
+)
from jaypore_ci.logging import logger
TZ = "UTC"
@@ -26,59 +33,17 @@ FIN_STATUSES = (Status.FAILED, Status.PASSED, Status.TIMEOUT, Status.SKIPPED)
PREFIX = "JAYPORE_"
-class Repo:
- """
- Contains information about the current repo.
- """
-
- sha: str
- branch: str
- remote: str
-
- def files_changed(self, target):
- "Returns list of files changed between current sha and target"
- return (
- subprocess.check_output(
- f"git diff --name-only {target} {self.sha}", shell=True
- )
- .decode()
- .strip()
- .split("\n")
- )
-
- @classmethod
- def from_env(cls):
- remote = (
- subprocess.check_output(
- "git remote -v | grep push | awk '{print $2}'", shell=True
- )
- .decode()
- .strip()
- )
- assert "https://" in remote, "Only https remotes supported"
- assert ".git" in remote
- branch = (
- subprocess.check_output(
- r"git branch | grep \* | awk '{print $2}'", shell=True
- )
- .decode()
- .strip()
- )
- sha = subprocess.check_output("git rev-parse HEAD", shell=True).decode().strip()
- return Repo(sha=sha, branch=branch, remote=remote)
-
-
class Job: # pylint: disable=too-many-instance-attributes
"""
This is the fundamental building block for running jobs.
Each job goes through a lifecycle defined by
:class:`jaypore_ci.interfaces.Status`.
- A job is run by an :class:`jaypore_ci.interfaces.Executor` as part of a
- :class:`jaypore_ci.jci.Pipeline`.
+ A job is run by an :class:`~jaypore_ci.interfaces.Executor` as part of a
+ :class:`~jaypore_ci.jci.Pipeline`.
It is never created manually. The correct way to create a job is to use
- :meth:`jaypore_ci.jci.Pipeline.job`.
+ :meth:`~jaypore_ci.jci.Pipeline.job`.
"""
def __init__(
@@ -238,10 +203,11 @@ class Pipeline: # pylint: disable=too-many-instance-attributes
def __init__( # pylint: disable=too-many-arguments
self,
+ *,
+ repo: Repo = None,
remote: Remote = None,
executor: Executor = None,
reporter: Reporter = None,
- *,
graph_direction: str = "TB",
poll_interval: int = 1,
**kwargs,
@@ -249,7 +215,12 @@ class Pipeline: # pylint: disable=too-many-instance-attributes
self.jobs = {}
self.services = []
self.should_pass_called = set()
- self.remote = remote if remote is not None else remotes.gitea.Gitea.from_env()
+ self.repo = repo if repo is not None else repos.Git.from_env()
+ self.remote = (
+ remote
+ if remote is not None
+ else remotes.gitea.Gitea.from_env(repo=self.repo)
+ )
self.executor = executor if executor is not None else executors.docker.Docker()
self.reporter = reporter if reporter is not None else reporters.text.Text()
self.graph_direction = graph_direction
@@ -266,7 +237,7 @@ class Pipeline: # pylint: disable=too-many-instance-attributes
)
self.executor.set_pipeline(self)
# ---
- kwargs["image"] = kwargs.get("image", "arjoonn/jaypore_ci:latest")
+ kwargs["image"] = kwargs.get("image", "arjoonn/jci:latest")
kwargs["timeout"] = kwargs.get("timeout", 15 * 60)
kwargs["env"] = kwargs.get("env", {})
kwargs["stage"] = "Pipeline"
diff --git a/jaypore_ci/remotes/__init__.py b/jaypore_ci/remotes/__init__.py
@@ -1,3 +1,4 @@
from .mock import Mock
from .gitea import Gitea
from .github import Github
+from .email import Email
diff --git a/jaypore_ci/remotes/email.py b/jaypore_ci/remotes/email.py
@@ -0,0 +1,154 @@
+"""
+An email remote.
+
+This is used to report pipeline status via email.
+Multiple updates appear as a single thread.
+"""
+import os
+import time
+import smtplib
+from html import escape as html_escape
+
+from email.headerregistry import Address
+from email.message import EmailMessage
+from pathlib import Path
+from urllib.parse import urlparse
+
+
+from jaypore_ci.interfaces import Remote, Repo
+from jaypore_ci.logging import logger
+
+
+class Email(Remote): # pylint: disable=too-many-instance-attributes
+ """
+ You can send pipeline status via email using this remote. In order to use it you
+ can specify the following environment variables in your secrets:
+
+ .. code-block:: console
+
+ JAYPORE_EMAIL_ADDR=email-account@gmail.com
+ JAYPORE_EMAIL_PASSWORD=some-app-password
+ JAYPORE_EMAIL_TO=myself@gmail.com,mailing-list@gmail.com
+ JAYPORE_EMAIL_FROM=noreply@gmail.com
+
+ If you're using something other than gmail, you can specify
+ `JAYPORE_EMAIL_HOST` and `JAYPORE_EMAIL_PORT` as well.
+
+ Once that is done you can supply this remote to your pipeline instead of
+ the usual gitea one.
+
+ .. code-block:: python
+
+ from jaypore_ci import jci, remotes, repos
+
+ git = repos.Git.from_env()
+ email = remotes.Email.from_env(repo=git)
+ with jci.Pipeline(repo=git, remote=email) as p:
+ pass
+ # Do something
+
+ """
+
+ @classmethod
+ def from_env(cls, *, repo: Repo) -> "Email":
+ """
+ Creates a remote instance from the environment.
+ """
+ remote = urlparse(repo.remote)
+ owner = Path(remote.path).parts[1]
+ name = Path(remote.path).parts[2].replace(".git", "")
+ return cls(
+ host=os.environ.get("JAYPORE_EMAIL_HOST", "smtp.gmail.com"),
+ port=int(os.environ.get("JAYPORE_EMAIL_PORT", 465)),
+ addr=os.environ["JAYPORE_EMAIL_ADDR"],
+ password=os.environ["JAYPORE_EMAIL_PASSWORD"],
+ email_to=os.environ["JAYPORE_EMAIL_TO"],
+ email_from=os.environ["JAYPORE_EMAIL_FROM"],
+ subject=f"JCI [{owner}/{name}] [{repo.branch} {repo.sha[:8]}]",
+ branch=repo.branch,
+ sha=repo.sha,
+ )
+
+ def __init__(
+ self,
+ *,
+ host: str,
+ port: int,
+ addr: str,
+ password: str,
+ email_to: str,
+ email_from: str,
+ subject: str,
+ publish_interval: int = 30,
+ **kwargs,
+ ): # pylint: disable=too-many-arguments
+ super().__init__(**kwargs)
+ # --- customer
+ self.host = host
+ self.port = port
+ self.addr = addr
+ self.password = password
+ self.email_to = email_to
+ self.email_from = email_from
+ self.subject = subject
+ self.timeout = 10
+ self.publish_interval = publish_interval
+ # ---
+ self.__smtp__ = None
+ self.__last_published_at__ = None
+ self.__last_report__ = None
+
+ @property
+ def smtp(self):
+ if self.__smtp__ is None:
+ smtp = smtplib.SMTP_SSL(self.host, self.port)
+ smtp.ehlo()
+ smtp.login(self.addr, self.password)
+ self.__smtp__ = smtp
+ return self.__smtp__
+
+ def logging(self):
+ """
+ Return's a logging instance with information about gitea bound to it.
+ """
+ return logger.bind(addr=self.addr, host=self.host, port=self.port)
+
+ def publish(self, report: str, status: str) -> None:
+ """
+ Will publish the report via email.
+
+ :param report: Report to write to remote.
+ :param status: One of ["pending", "success", "error", "failure",
+ "warning"] This is the dot next to each commit in gitea.
+ """
+ assert status in ("pending", "success", "error", "failure", "warning")
+ if (
+ self.__last_published_at__ is not None
+ and (time.time() - self.__last_published_at__) < self.publish_interval
+ ):
+ return
+ if self.__last_report__ == report:
+ return
+ self.__last_report__ = report
+ self.__last_published_at__ = time.time()
+ # Let's send the email
+ msg = EmailMessage()
+ msg["Subject"] = self.subject
+ msg["From"] = Address("JayporeCI", "JayporeCI", self.email_from)
+ msg["To"] = self.email_to
+ msg.set_content(report)
+ msg.add_alternative(
+ f"<html><body><pre>{html_escape(report)}</pre></body></html>",
+ subtype="html",
+ )
+ try:
+ self.smtp.send_message(msg)
+ except Exception as e: # pylint: disable=broad-except
+ self.logging().exception(e)
+ self.__last_published_at__ = time.time()
+ self.logging().info(
+ "Report published",
+ subject=self.subject,
+ email_from=self.email_from,
+ email_to=self.email_to,
+ )
diff --git a/jaypore_ci/remotes/gitea.py b/jaypore_ci/remotes/gitea.py
@@ -4,13 +4,12 @@ A gitea remote git host.
This is used to report pipeline status to the remote.
"""
import os
-import subprocess
from pathlib import Path
from urllib.parse import urlparse
import requests
-from jaypore_ci.interfaces import Remote, RemoteApiFailed
+from jaypore_ci.interfaces import Remote, RemoteApiFailed, Repo
from jaypore_ci.logging import logger
@@ -20,7 +19,7 @@ class Gitea(Remote): # pylint: disable=too-many-instance-attributes
"""
@classmethod
- def from_env(cls):
+ def from_env(cls, *, repo: Repo) -> "Gitea":
"""
Creates a remote instance from the environment.
It will:
@@ -30,36 +29,16 @@ class Gitea(Remote): # pylint: disable=too-many-instance-attributes
- Create a new pull request for that branch
- Allow posting updates using the gitea token provided
"""
- remote = (
- subprocess.check_output(
- "git remote -v | grep push | awk '{print $2}'", shell=True
- )
- .decode()
- .strip()
- )
- assert "https://" in remote, "Only https remotes supported"
- assert ".git" in remote
- remote = urlparse(remote)
- branch = (
- subprocess.check_output(
- r"git branch | grep \* | awk '{print $2}'", shell=True
- )
- .decode()
- .strip()
- )
- os.environ["JAYPORE_COMMIT_BRANCH"] = branch
- sha = subprocess.check_output("git rev-parse HEAD", shell=True).decode().strip()
- os.environ["JAYPORE_COMMIT_SHA"] = sha
- owner = Path(remote.path).parts[1]
- repo = Path(remote.path).parts[2].replace(".git", "")
- token = os.environ["JAYPORE_GITEA_TOKEN"]
+ os.environ["JAYPORE_COMMIT_BRANCH"] = repo.branch
+ os.environ["JAYPORE_COMMIT_SHA"] = repo.sha
+ remote = urlparse(repo.remote)
return cls(
root=f"{remote.scheme}://{remote.netloc}",
- owner=owner,
- repo=repo,
- branch=branch,
- token=token,
- sha=sha,
+ owner=Path(remote.path).parts[1],
+ repo=Path(remote.path).parts[2].replace(".git", ""),
+ branch=repo.branch,
+ token=os.environ["JAYPORE_GITEA_TOKEN"],
+ sha=repo.sha,
)
def __init__(
diff --git a/jaypore_ci/remotes/github.py b/jaypore_ci/remotes/github.py
@@ -4,13 +4,12 @@ A github remote git host.
This is used to report pipeline status to the remote.
"""
import os
-import subprocess
from pathlib import Path
from urllib.parse import urlparse
import requests
-from jaypore_ci.interfaces import Remote, RemoteApiFailed
+from jaypore_ci.interfaces import Remote, RemoteApiFailed, Repo
from jaypore_ci.logging import logger
@@ -27,7 +26,7 @@ class Github(Remote): # pylint: disable=too-many-instance-attributes
}
@classmethod
- def from_env(cls):
+ def from_env(cls, *, repo: Repo) -> "Github":
"""
Creates a remote instance from the environment.
It will:
@@ -37,36 +36,16 @@ class Github(Remote): # pylint: disable=too-many-instance-attributes
- Create a new pull request for that branch
- Allow posting updates using the gitea token provided
"""
- remote = (
- subprocess.check_output(
- "git remote -v | grep push | awk '{print $2}'", shell=True
- )
- .decode()
- .strip()
- )
- assert "https://github.com" in remote, "Only https remotes supported"
- assert ".git" in remote
- remote = urlparse(remote)
- branch = (
- subprocess.check_output(
- r"git branch | grep \* | awk '{print $2}'", shell=True
- )
- .decode()
- .strip()
- )
- os.environ["JAYPORE_COMMIT_BRANCH"] = branch
- sha = subprocess.check_output("git rev-parse HEAD", shell=True).decode().strip()
- os.environ["JAYPORE_COMMIT_SHA"] = sha
- owner = Path(remote.path).parts[1]
- repo = Path(remote.path).parts[2].replace(".git", "")
- token = os.environ["JAYPORE_GITHUB_TOKEN"]
+ remote = urlparse(repo.remote)
+ os.environ["JAYPORE_COMMIT_BRANCH"] = repo.branch
+ os.environ["JAYPORE_COMMIT_SHA"] = repo.sha
return cls(
root="https://api.github.com",
- owner=owner,
- repo=repo,
- branch=branch,
- token=token,
- sha=sha,
+ owner=Path(repo.remote.path).parts[1],
+ repo=Path(remote.path).parts[2].replace(".git", ""),
+ branch=repo.branch,
+ token=os.environ["JAYPORE_GITHUB_TOKEN"],
+ sha=repo.sha,
)
def __init__(
diff --git a/jaypore_ci/remotes/mock.py b/jaypore_ci/remotes/mock.py
@@ -6,7 +6,7 @@ This is used to report pipeline status to the remote.
import os
-from jaypore_ci.interfaces import Remote
+from jaypore_ci.interfaces import Remote, Repo
from jaypore_ci.logging import logger
@@ -16,7 +16,7 @@ class Mock(Remote): # pylint: disable=too-many-instance-attributes
"""
@classmethod
- def from_env(cls):
+ def from_env(cls, *, repo: Repo):
return cls(branch=os.environ["JAYPORE_BRANCH"], sha=os.environ["JAYPORE_SHA"])
def logging(self):
diff --git a/jaypore_ci/repos/__init__.py b/jaypore_ci/repos/__init__.py
@@ -0,0 +1,2 @@
+from .git import Git
+from .mock import Mock
diff --git a/jaypore_ci/repos/git.py b/jaypore_ci/repos/git.py
@@ -0,0 +1,43 @@
+import subprocess
+from typing import List
+
+from jaypore_ci.interfaces import Repo
+
+
+class Git(Repo):
+ def files_changed(self, target: str) -> List[str]:
+ "Returns list of files changed between current sha and target"
+ return (
+ subprocess.check_output(
+ f"git diff --name-only {target} {self.sha}", shell=True
+ )
+ .decode()
+ .strip()
+ .split("\n")
+ )
+
+ @classmethod
+ def from_env(cls) -> "Git":
+ """
+ Gets repo status from the environment and git repo on disk.
+ """
+ remote = (
+ subprocess.check_output(
+ "git remote -v | grep push | grep https | awk '{print $2}'", shell=True
+ )
+ .decode()
+ .strip()
+ )
+ assert "https://" in remote, "Only https remotes supported"
+ assert ".git" in remote
+ # NOTE: Later on perhaps we should support non-https remotes as well
+ # since JCI does not actually do anything with the remote.
+ branch = (
+ subprocess.check_output(
+ r"git branch | grep \* | awk '{print $2}'", shell=True
+ )
+ .decode()
+ .strip()
+ )
+ sha = subprocess.check_output("git rev-parse HEAD", shell=True).decode().strip()
+ return Repo(sha=sha, branch=branch, remote=remote)
diff --git a/jaypore_ci/repos/mock.py b/jaypore_ci/repos/mock.py
@@ -0,0 +1,20 @@
+from typing import List
+
+from jaypore_ci.interfaces import Repo
+
+
+class Mock(Repo):
+ def __init__(self, *, files_changed, **kwargs):
+ super().__init__(**kwargs)
+ self.files_changed = files_changed
+
+ def files_changed(self, target: str) -> List[str]:
+ "Returns list of files changed between current sha and target"
+ return self.files_changed
+
+ @classmethod
+ def from_env(cls, **kwargs) -> "Mock":
+ """
+ Gets repo status from the environment and git repo on disk.
+ """
+ return cls(**kwargs)
diff --git a/pyproject.toml b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "jaypore_ci"
-version = "0.2.9"
+version = "0.2.10"
description = ""
authors = ["arjoonn sharma <arjoonn.94@gmail.com>"]
diff --git a/secrets/bin/edit_env.sh b/secrets/bin/edit_env.sh
@@ -10,17 +10,19 @@ main (){
KEY_FILE=$(echo "$SECRETS/$NAME.key")
ENC_FILE=$(echo "$SECRETS/$NAME.enc")
PLAINTEXT_FILE=$(echo "$SECRETS/$NAME.plaintext")
- echo $BIN
- echo $SECRETS
- echo $KEY_FILE
- echo $ENC_FILE
- echo $PLAINTEXT_FILE
+ export SOPS_AGE_KEY_FILE=$KEY_FILE
+ echo "BIN = $BIN"
+ echo "SECRETS = $SECRETS"
+ echo "KEY = $KEY_FILE"
+ echo "SOPS KEY = $SOPS_AGE_KEY_FILE"
+ echo "ENC = $ENC_FILE"
+ echo "PLAIN = $PLAINTEXT_FILE"
PATH="$BIN:$PATH"
- if [[ -f "$SECRETS/$NAME.enc" ]]; then
- SOPS_AGE_KEY_FILE=$KEY_FILE sops --decrypt --input-type dotenv --output-type dotenv $ENC_FILE > $PLAINTEXT_FILE
+ if [[ -f "$ENC_FILE" ]]; then
+ sops --decrypt --input-type dotenv --output-type dotenv "$ENC_FILE" > "$PLAINTEXT_FILE"
fi
- vim $PLAINTEXT_FILE
- sops --input-type dotenv --output-type dotenv --encrypt --age $(age-keygen -y $KEY_FILE) $PLAINTEXT_FILE > $ENC_FILE
- rm $PLAINTEXT_FILE
+ vim "$PLAINTEXT_FILE"
+ sops --input-type dotenv --output-type dotenv --encrypt --age $(age-keygen -y "$KEY_FILE") "$PLAINTEXT_FILE" > "$ENC_FILE"
+ rm "$PLAINTEXT_FILE"
}
(main $1)
diff --git a/secrets/ci.enc b/secrets/ci.enc
@@ -1,12 +1,16 @@
-JAYPORE_DOCKER_USER=ENC[AES256_GCM,data:bWzVvBoSwg==,iv:YZWgrVzgYAkV0UtBmMQOpcDPXCGl+RTFXGeN4+FaT8U=,tag:snItFIFsT6j/rsqJjs9UTg==,type:str]
-JAYPORE_DOCKER_PWD=ENC[AES256_GCM,data:w+228n0Lu0jF6mdbo2Tl98ata8Mh7EAUiyPcDqnicpZYjGTY,iv:140Ah/i5uI9y9ZpurQFuJ0EAOSz5U2NcMT2eRZnLoI0=,tag:FTqPc+zy+aspiRKAubeGWQ==,type:str]
-JAYPORE_NETLIFY_TOKEN=ENC[AES256_GCM,data:sdbG9uX53iNee1i3OVS5x5dehfDB3zvwRv1C9ziUTOCqhG4pxcb3D7+jWg==,iv:XiS/FrUAskxO8P3kpgMCn4R2OXAqOb/JuZMNnHIa2SI=,tag:Plo5Tm6mP/734EYS2JlLqQ==,type:str]
-JAYPORE_NETLIFY_SITEID=ENC[AES256_GCM,data:K70Mup4c95eU3oCdY1yZwBNl2pN33RJA1SEnYbZ1NLarE/N6,iv:434UV0BG39eUwuI8TmciO6wNQbmnNZx4VtY/C8iL6R4=,tag:3+s7RIDHpogczYg7VmBanQ==,type:str]
-JAYPORE_PYPI_TOKEN=ENC[AES256_GCM,data:TgiQOevajULMgnj0RwqaZ54NUbWDOOc/w9lHY3qc50cyZ+p3sIuUjmNQ+xM+aCLh68OQotRb7bzr+A999/cy1EcIdcsBJJvU4qjHGvFJ4YxsP+dgC0QeXerXqdLxCClOZ9NQ368ffKo4Htxj1mkZE2guXvYUhqR32YQ83MgKRWY8WgCtLm1xnstAAZnAOm+CHKN5jPb1jhXWXuhZk8dsGUCBDyKvQbwCFYw0DhByjQ+NSkLB1K/+s8iEla6UzBaA5AgGF0RvBSSegEhj14BACcA=,iv:UUrkczg4//aNRUSH+ZDwNwEDY8vMO5xGOHH+dXt3Suc=,tag:pIxet3/a1F5gOMDHg9ma9Q==,type:str]
-JAYPORE_GITEA_TOKEN=ENC[AES256_GCM,data:hya5PF/zQbkhplmiYHBYbpWQaDxavPs15aHalftvyeuBe5BGKdFtew==,iv:za+/uLXPLD200MTcqDlBdO7aJnDw7eAF123p9yvpeK4=,tag:AUaUcSCgE/YiuUHGVHoH/w==,type:str]
+JAYPORE_DOCKER_USER=ENC[AES256_GCM,data:oC92MBM2hA==,iv:1GAxCOZZv0XsiX3PY3vYHnG9J8mcCwJDgNsPdvvRKFQ=,tag:v8AywYAOzvjRtWqlDBeM0g==,type:str]
+JAYPORE_DOCKER_PWD=ENC[AES256_GCM,data:CYOp9N93tnQIK+8CmMld/8loFErRvaP9BIaneUTDmgiAutpv,iv:ZIKzJaUogjGcbvophgeNw8CZvTDIBHuVaHq3ichAb9U=,tag:Sg0M8f4Nb7xWdMgwm27e7Q==,type:str]
+JAYPORE_NETLIFY_TOKEN=ENC[AES256_GCM,data:6UpWZ0ZWLKraLs1tP3wz7JbAA7nqu+afOtigAQv7FaYS8aTuM3/ozieayQ==,iv:AJXlNpKYHcg8Nh1fAop58MBmV0s/gmjxazuXtWLQqyE=,tag:91hPgDWAWYuTmnZ+Coo2Og==,type:str]
+JAYPORE_NETLIFY_SITEID=ENC[AES256_GCM,data:z4QaJ4xUM490WViYv4Acau//pkjgWCQ7kNfW3g4qASw6qLR8,iv:IPhuWvBWZxtYiL5XtQFEnR6RxOiezvc2hISdgLaBzp8=,tag:Yb8jMn2n6HK4ybqgsZNR9Q==,type:str]
+JAYPORE_PYPI_TOKEN=ENC[AES256_GCM,data:FPk9CBTboAi2H0afgWtV59IHLOC8xx3WxhN/gIzTcC+lSlXsCyyM1Zio63aWlfufBk4FJcJhpFopVVpijRGzHCpHgC/hYyUKwBO6wenNktM9Ul8LRkQJk7KVvn5cLjAS6yK/vutr3/SHXkzgef3B7EL1J8jjRjDpQQvadDyLPOf20eduWnpwp5fQa6y/KdwhDW36Z6GEzNLbUeevGeeIaidYTVTPacbIEcKh04OUGc5URro8oFv7cBzmR6srxFyqrHNJZtG1ZhZwuPVPneLj+ck=,iv:ujxVdymiIHlUCQEByVVuQqKmCvWA0P7hnxQ73vKnknk=,tag:ih1WgEOTcQmeIxtd80XFYg==,type:str]
+JAYPORE_GITEA_TOKEN=ENC[AES256_GCM,data:qQuApRUUZ5GygKg13HoddtlQY20+0yrptaCtUYHMFEl793tXvA+4XQ==,iv:QwHIUQ+5OpGxzCf8aA9bq1hLtUNaKZdAU/5TWPSmlCU=,tag:LUTvMn1EZybQUHscCIKAew==,type:str]
+JAYPORE_EMAIL_ADDR=ENC[AES256_GCM,data:xkTmiw==,iv:m8XmWl41mv10DMwc7d3oOWMOxnQf2/6VtK5T2Gws49U=,tag:sJeT0maZP61rphdpa0VOng==,type:str]
+JAYPORE_EMAIL_PASSWORD=ENC[AES256_GCM,data:eyPc/Q==,iv:uj6drBxAobrtKgF9VXDJdWCMTX57YOu5WFW7wQIWzFk=,tag:3uAljYsvCQhZ7/FZQQHjXw==,type:str]
+JAYPORE_EMAIL_TO=ENC[AES256_GCM,data:yEy5Lw==,iv:mij/qk1P/q/VzWSSE7NW5RGsO7Fpgxof0A0pm4aqYmQ=,tag:clf/3fybvqFTGZj/fOCrSA==,type:str]
+JAYPORE_EMAIL_FROM=ENC[AES256_GCM,data:YSoI7Q==,iv:6celjipnC9rNPKAb++hpY4x1TEW1ul/jnUtP6m8EyFE=,tag:6MvYSoPkCerpRhn+jSsd0Q==,type:str]
sops_version=3.7.3
-sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzVCtDNkZKVDRmSUVrdlR4\nczEyK1ViVlhpYzJydkR6R2FZY0JYVC9qUlQwCm41S1dkbWRWMFFFWDhKcmcwRTZI\nTFMvUzJ0RXNOYWtHYlNlSHJHVnd1RjQKLS0tIDBGUDNDSnFsak9mMm1SNnpuREY5\nSGRJVVI4ZW91SkdHYUNQeXVJUU9lS1kKvs9P+gI6AN8GWwe2opau/F4d9noxd2mm\nhlQySflV7qKMhKXdt+cct4/atsBLB9BKvcaHBx2BSYBjNA6MwGIirw==\n-----END AGE ENCRYPTED FILE-----\n
-sops_mac=ENC[AES256_GCM,data:xErAenO+DaTNk/W4OOqIVNafdVmLMzVDOKb3GRzEjZBuLNNUkNBRVVAyQmkr6+9IeqINnpp+285wg9h8Qf5BPAfSScI5i8Kj/GiqHmiriE//4+bub9BYg+kdP7B3idukGoeJEGUrMBhENUuS7Z5TYgI7UgOlKXSHWWqBgn+MkWo=,iv:25fjibgI3Xd19h+SMQrJbNpJc5QoB+kwfZxo4LXydG0=,tag:lW2GPmTvq8h2Tc84F9Il1A==,type:str]
+sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxeDRPY1RjanBseFVWcVdW\nZWlFaUk3dnQyUmYzck5iUTc1Z0RvMHZyamtnCnU0aUI0cHo3a2FuRERyV0pkc05x\nWnBseURYK0xFcWxnTklmRzdoQ3BoencKLS0tIFhMUk44dDhweEpTNnJWNGZqWWRS\nclVEOTZUYllmMVBBdjkvZjVtVkVHcHMKonS5h3nfmAYNwz7zPTd0eA+eC7MffKTC\nXfPDIveZrpFJLz0YDdPiFD2sORFlTZog8bitzhgY1MZwQNqE8iZQjw==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1u0zd477nnqqausg4vtxl3laxz73t5tgt9qw8enmpeeadcmes3eusw3v3m9
+sops_lastmodified=2023-02-19T07:33:53Z
+sops_mac=ENC[AES256_GCM,data:J8cqAfeAMvwA8DvtwiPbCjlUllOdgZUcgExK8HENtXhBBLEmaznI2tfB7tF2CSMLg+y9lLL8pmqQQRMr6JMCEbSSetRb0yvV2T1r9gpe5fZ5dd65gD8i1OXeAivqeeaRf8H7cGrb7wnWLn564fq26J6JR8LKahjj6+rzpawXzig=,iv:TDDm8g0bSCNSHWH+brQPUSvC1QHsl/gQ6l1JnVftxXo=,tag:eRRUTYH1+XIB/GinN7HWvQ==,type:str]
sops_unencrypted_suffix=_unencrypted
-sops_lastmodified=2023-02-02T14:21:37Z
diff --git a/tests/conftest.py b/tests/conftest.py
@@ -1,17 +1,20 @@
import pytest
-from jaypore_ci import jci, executors, remotes, reporters
+from jaypore_ci import jci, executors, remotes, reporters, repos
@pytest.fixture(
scope="function", params=[reporters.Text, reporters.Mock, reporters.Markdown]
)
def pipeline(request):
+ repo = repos.Mock.from_env(
+ files_changed=[], branch="test_branch", sha="fake_sha", remote="fake_remote"
+ )
executor = executors.Mock()
- remote = remotes.Mock(branch="test_branch", sha="fake")
+ remote = remotes.Mock(branch=repo.branch, sha=repo.sha)
reporter = request.param()
p = jci.Pipeline(
- executor=executor, remote=remote, reporter=reporter, poll_interval=0
+ repo=repo, executor=executor, remote=remote, reporter=reporter, poll_interval=0
)
p.render_report = lambda: ""
yield p