本来, gitlab 是自带邮件通知, 但是需要配置: https://blog.csdn.net/liuruiqun/article/details/50000213
不过, 正好配置人没弄过这个, 也懒得麻烦人家了。
做了一个小程序, 来实现这个功能。
基本思路:
1. 将项目的信息保存到 sqlite 表中;
2. C#调用 Proccess, 轮询检测项目的最后一条日志,如果日志的提交时间 > sqlite 对应项目的最后时间(初始置为 1900-01-01), 则给配置表中相关的人发邮件;
项目解决方案
Sqlite 表结构:
DROP TABLE IF EXISTS "project_data";
CREATE TABLE "project_data" (
"projectId" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"projectName" nvarchar(100) NOT NULL,
"localPath" nvarchar(500) NOT NULL,
"lastUpdateTime" datetime NOT NULL,
"lastLog" nvarchar(4000) NOT NULL,
"emailToList" varchar(400) NOT NULL,
"isEnabled" bit NOT NULL
);
注意事项
1. 邮箱、密码得改成自己的;
2. 可以用 Windows计划任务 或 SQL Server的代理作业来调用 ( 我本人是用自己写的通用定时服务来调用 ) ;
主要代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GitNotifyCommon.Model;
using GitNotifyCommon.DAL;
using GitNotifyCommon;
using System.Diagnostics;
using System.Globalization;
namespace GitNotifyCommon
{
public class WatcherGit
{
public static void Run()
{
//1. 获取所有的项目
List<Project> list = ProjectDAL.GetList();
if (list == null || list.Count == 0)
{
Logger.Singleton.Error("未获取到任何项目");
return;
}
//2. 依次执行,得到相关的日志,并对比,如果有新的则发送邮件
foreach (Project item in list)
{
ExecGit(item);
}
}
private static void ExecGit(Project item)
{
try
{
using (Process pro = new Process())
{
System.Console.InputEncoding = System.Text.Encoding.UTF8;
Process p = new Process();
p.StartInfo.WorkingDirectory = item.LocalPath;
p.StartInfo.FileName = CommonConfig.LocalGitCmd;
p.StartInfo.Arguments = "log -1";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
p.Start();
string info = p.StandardOutput.ReadToEnd();
p.WaitForExit();
SaveInfo(item, info);
//拉取最新版本
p.StartInfo.Arguments = "pull";
p.Start();
p.WaitForExit();
}
}
catch (Exception ex)
{
Logger.Singleton.FatalFormat("执行 git 出错, {0}", ex, ex.Message );
}
}
private static string GetDateString(string[] arr, ref int dateIdx)
{
int j = -1;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i].StartsWith("Date:"))
{
j = i;
break;
}
}
if (j == -1)
return null;
dateIdx = j;
string dateString = arr[j].Replace("Date:", "").Replace("+0800", "").Trim();
dateString = dateString.Substring(dateString.IndexOf(" ")).Trim();
string[] monthArr = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
string[] arr2 = dateString.Split(' ');
int month = -1;
for (int i = 0; i < monthArr.Length; i++)
{
string monthStr = monthArr[i];
if (monthStr == arr2[0])
{
month = i;
break;
}
}
dateString = string.Format("{0}-{1}-{2} {3}", arr2[3], month, arr2[1], arr2[2]);
return dateString;
}
private static void SaveInfo(Project item, string info)
{
string[] arr = info.Split('\n');
int dateIdx = 0;
string dateString = GetDateString(arr, ref dateIdx);
if (arr.Length < 3 || dateString == null)
{
Logger.Singleton.ErrorFormat("字符串中获取不到正确的日期:\r\n{0}", info);
return;
}
DateTime dt = DateTime.MinValue;
if (!DateTime.TryParse(dateString, out dt))
{
Logger.Singleton.FatalFormat("日期转换错误: {0}",dateString);
return;
}
if (dt == item.LastUpdateTime)
{
Logger.Singleton.DebugFormat("ProjectName:{0}, LastUpdateTime: {1} 无更新。", item.ProjectName, dt);
return;
}
Logger.Singleton.InfoFormat("ProjectName:{0}, LastUpdateTime: {1} 有更新。", item.ProjectName, dt);
//如果 item 原日期> 1900-01-01, 不是原始记录,发邮件
if (item.LastUpdateTime.Year > 1900 && dt>item.LastUpdateTime)
{
string commitId = arr[0];
string author = arr[1];
string commitDate = arr[dateIdx];
StringBuilder sbDesc = new StringBuilder();
for (int j = dateIdx+1; j < arr.Length; j++)
{
sbDesc.AppendFormat("{0}<br/>",arr[j]);
}
string commitDesc = sbDesc.ToString();
string html = string.Format(
@"<style>.hr2 {{
height: 3px;
border: none;
border-top: 3px double #33ccff;
width: 100%;
}}</style>
<div>
ProjectName: {0}<br/>
{1}<br/>
{2}<br/>
Date: {3}<br/>
<hr class='hr2' />
<span style='color:blue;'>{4}</span>
</div>"
, item.ProjectName
, commitId
, author.Replace("<", "<").Replace(">", ">")
, dt.ToString("yyyy-MM-dd HH:mm:ss")
, commitDesc
);
EmailHelper email = new EmailHelper(item.EmailToList
, string.Format("【{0}】 git new commit by: {1}", item.ProjectName , author.Replace("Author:",""))
, true
, html
);
email.Send();
}
//如果是新记录 更新记录
item.LastUpdateTime = dt;
item.LastLog = info;
ProjectDAL.Update(item);
}
}
}
using System;
using System.Data;
using System.Text.RegularExpressions;
using System.Xml;
using System.IO;
using System.Collections;
using System.Data.SQLite;
namespace GitNotifyCommon
{
/// <summary>
/// SQLiteHelper is a utility class similar to "SQLHelper" in MS
/// Data Access Application Block and follows similar pattern.
/// </summary>
public class SQLiteHelper
{
/// <summary>
/// Creates a new <see cref="SQLiteHelper"/> instance. The ctor is marked private since all members are static.
/// </summary>
private SQLiteHelper()
{
}
/// <summary>
/// Creates the command.
/// </summary>
/// <param name="connection">Connection.</param>
/// <param name="commandText">Command text.</param>
/// <param name="commandParameters">Command parameters.</param>
/// <returns>SQLite Command</returns>
public static SQLiteCommand CreateCommand(SQLiteConnection connection, string commandText, params SQLiteParameter[] commandParameters)
{
SQLiteCommand cmd = new SQLiteCommand(commandText, connection);
if (commandParameters.Length > 0)
{
foreach (SQLiteParameter parm in commandParameters)
cmd.Parameters.Add(parm);
}
return cmd;
}
/// <summary>
/// Creates the command.
/// </summary>
/// <param name="connectionString">Connection string.</param>
/// <param name="commandText">Command text.</param>
/// <param name="commandParameters">Command parameters.</param>
/// <returns>SQLite Command</returns>
public static SQLiteCommand CreateCommand(string connectionString, string commandText, params SQLiteParameter[] commandParameters)
{
SQLiteConnection cn = new SQLiteConnection(connectionString);
SQLiteCommand cmd = new SQLiteCommand(commandText, cn);
if (commandParameters.Length > 0)
{
foreach (SQLiteParameter parm in commandParameters)
cmd.Parameters.Add(parm);
}
return cmd;
}
/// <summary>
/// Creates the parameter.
/// </summary>
/// <param name="parameterName">Name of the parameter.</param>
/// <param name="parameterType">Parameter type.</param>
/// <param name="parameterValue">Parameter value.</param>
/// <returns>SQLiteParameter</returns>
public static SQLiteParameter CreateParameter(string parameterName, System.Data.DbType parameterType, object parameterValue)
{
SQLiteParameter parameter = new SQLiteParameter();
parameter.DbType = parameterType;
parameter.ParameterName = parameterName;
parameter.Value = parameterValue;
return parameter;
}
/// <summary>
/// Shortcut method to execute dataset from SQL Statement and object[] arrray of parameter values
/// </summary>
/// <param name="connectionString">SQLite Connection string</param>
/// <param name="commandText">SQL Statement with embedded "@param" style parameter names</param>
/// <param name="paramList">object[] array of parameter values</param>
/// <returns></returns>
public static DataSet ExecuteDataSet(string connectionString, string commandText, object[] paramList)
{
SQLiteConnection cn = new SQLiteConnection(connectionString);
SQLiteCommand cmd = cn.CreateCommand();
cmd.CommandText = commandText;
if (paramList != null)
{
AttachParameters(cmd, commandText, paramList);
}
DataSet ds = new DataSet();
if (cn.State == ConnectionState.Closed)
cn.Open();
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
da.Fill(ds);
da.Dispose();
cmd.Dispose();
cn.Close();
return ds;
}
/// <summary>
/// Shortcut method to execute dataset from SQL Statement and object[] arrray of parameter values
/// </summary>
/// <param name="cn">Connection.</param>
/// <param name="commandText">Command text.</param>
/// <param name="paramList">Param list.</param>
/// <returns></returns>
public static DataSet ExecuteDataSet(SQLiteConnection cn, string commandText, object[] paramList)
{
SQLiteCommand cmd = cn.CreateCommand();
cmd.CommandText = commandText;
if (paramList != null)
{
AttachParameters(cmd, commandText, paramList);
}
DataSet ds = new DataSet();
if (cn.State == ConnectionState.Closed)
cn.Open();
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
da.Fill(ds);
da.Dispose();
cmd.Dispose();
cn.Close();
return ds;
}
/// <summary>
/// Executes the dataset from a populated Command object.
/// </summary>
/// <param name="cmd">Fully populated SQLiteCommand</param>
/// <returns>DataSet</returns>
public static DataSet ExecuteDataset(SQLiteCommand cmd)
{
if (cmd.Connection.State == ConnectionState.Closed)
cmd.Connection.Open();
DataSet ds = new DataSet();
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
da.Fill(ds);
da.Dispose();
cmd.Connection.Close();
cmd.Dispose();
return ds;
}
/// <summary>
/// Executes the dataset in a SQLite Transaction
/// </summary>
/// <param name="transaction">SQLiteTransaction. Transaction consists of Connection, Transaction, /// and Command, all of which must be created prior to making this method call. </param>
/// <param name="commandText">Command text.</param>
/// <param name="commandParameters">Sqlite Command parameters.</param>
/// <returns>DataSet</returns>
/// <remarks>user must examine Transaction Object and handle transaction.connection .Close, etc.</remarks>
public static DataSet ExecuteDataset(SQLiteTransaction transaction, string commandText, params SQLiteParameter[] commandParameters)
{
if (transaction == null) throw new ArgumentNullException("transaction");
if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rolled back or committed, please provide an open transaction.", "transaction");
IDbCommand cmd = transaction.Connection.CreateCommand();
cmd.CommandText = commandText;
foreach (SQLiteParameter parm in commandParameters)
{
cmd.Parameters.Add(parm);
}
if (transaction.Connection.State == ConnectionState.Closed)
transaction.Connection.Open();
DataSet ds = ExecuteDataset((SQLiteCommand)cmd);
return ds;
}
/// <summary>
/// Executes the dataset with Transaction and object array of parameter values.
/// </summary>
/// <param name="transaction">SQLiteTransaction. Transaction consists of Connection, Transaction, /// and Command, all of which must be created prior to making this method call. </param>
/// <param name="commandText">Command text.</param>
/// <param name="commandParameters">object[] array of parameter values.</param>
/// <returns>DataSet</returns>
/// <remarks>user must examine Transaction Object and handle transaction.connection .Close, etc.</remarks>
public static DataSet ExecuteDataset(SQLiteTransaction transaction, string commandText, object[] commandParameters)
{
if (transaction == null) throw new ArgumentNullException("transaction");
if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rolled back or committed, please provide an open transaction.", "transaction");
IDbCommand cmd = transaction.Connection.CreateCommand();
cmd.CommandText = commandText;
AttachParameters((SQLiteCommand)cmd, cmd.CommandText, commandParameters);
if (transaction.Connection.State == ConnectionState.Closed)
transaction.Connection.Open();
DataSet ds = ExecuteDataset((SQLiteCommand)cmd);
return ds;
}
#region UpdateDataset
/// <summary>
/// Executes the respective command for each inserted, updated, or deleted row in the DataSet.
/// </summary>
/// <remarks>
/// e.g.:
/// UpdateDataset(conn, insertCommand, deleteCommand, updateCommand, dataSet, "Order");
/// </remarks>
/// <param name="insertCommand">A valid SQL statement to insert new records into the data source</param>
/// <param name="deleteCommand">A valid SQL statement to delete records from the data source</param>
/// <param name="updateCommand">A valid SQL statement used to update records in the data source</param>
/// <param name="dataSet">The DataSet used to update the data source</param>
/// <param name="tableName">The DataTable used to update the data source.</param>
public static void UpdateDataset(SQLiteCommand insertCommand, SQLiteCommand deleteCommand, SQLiteCommand updateCommand, DataSet dataSet, string tableName)
{
if (insertCommand == null) throw new ArgumentNullException("insertCommand");
if (deleteCommand == null) throw new ArgumentNullException("deleteCommand");
if (updateCommand == null) throw new ArgumentNullException("updateCommand");
if (tableName == null || tableName.Length == 0) throw new ArgumentNullException("tableName");
// Create a SQLiteDataAdapter, and dispose of it after we are done
using (SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter())
{
// Set the data adapter commands
dataAdapter.UpdateCommand = updateCommand;
dataAdapter.InsertCommand = insertCommand;
dataAdapter.DeleteCommand = deleteCommand;
// Update the dataset changes in the data source
dataAdapter.Update(dataSet, tableName);
// Commit all the changes made to the DataSet
dataSet.AcceptChanges();
}
}
#endregion
/// <summary>
/// ShortCut method to return IDataReader
/// NOTE: You should explicitly close the Command.connection you passed in as
/// well as call Dispose on the Command after reader is closed.
/// We do this because IDataReader has no underlying Connection Property.
/// </summary>
/// <param name="cmd">SQLiteCommand Object</param>
/// <param name="commandText">SQL Statement with optional embedded "@param" style parameters</param>
/// <param name="paramList">object[] array of parameter values</param>
/// <returns>IDataReader</returns>
public static IDataReader ExecuteReader(SQLiteCommand cmd, string commandText, object[] paramList)
{
if (cmd.Connection == null)
throw new ArgumentException("Command must have live connection attached.", "cmd");
cmd.CommandText = commandText;
AttachParameters(cmd, commandText, paramList);
if (cmd.Connection.State == ConnectionState.Closed)
cmd.Connection.Open();
IDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return rdr;
}
/// <summary>
/// Shortcut to ExecuteNonQuery with SqlStatement and object[] param values
/// </summary>
/// <param name="connectionString">SQLite Connection String</param>
/// <param name="commandText">Sql Statement with embedded "@param" style parameters</param>
/// <param name="paramList">object[] array of parameter values</param>
/// <returns></returns>
public static int ExecuteNonQuery(string connectionString, string commandText, params object[] paramList)
{
SQLiteConnection cn = new SQLiteConnection(connectionString);
SQLiteCommand cmd = cn.CreateCommand();
cmd.CommandText = commandText;
AttachParameters(cmd, commandText, paramList);
if (cn.State == ConnectionState.Closed)
cn.Open();
int result = cmd.ExecuteNonQuery();
cmd.Dispose();
cn.Close();
return result;
}
public static int ExecuteNonQuery(SQLiteConnection cn, string commandText, params object[] paramList)
{
SQLiteCommand cmd = cn.CreateCommand();
cmd.CommandText = commandText;
AttachParameters(cmd, commandText, paramList);
if (cn.State == ConnectionState.Closed)
cn.Open();
int result = cmd.ExecuteNonQuery();
cmd.Dispose();
cn.Close();
return result;
}
/// <summary>
/// Executes non-query sql Statment with Transaction
/// </summary>
/// <param name="transaction">SQLiteTransaction. Transaction consists of Connection, Transaction, /// and Command, all of which must be created prior to making this method call. </param>
/// <param name="commandText">Command text.</param>
/// <param name="paramList">Param list.</param>
/// <returns>Integer</returns>
/// <remarks>user must examine Transaction Object and handle transaction.connection .Close, etc.</remarks>
public static int ExecuteNonQuery(SQLiteTransaction transaction, string commandText, params object[] paramList)
{
if (transaction == null) throw new ArgumentNullException("transaction");
if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rolled back or committed, please provide an open transaction.", "transaction");
IDbCommand cmd = transaction.Connection.CreateCommand();
cmd.CommandText = commandText;
AttachParameters((SQLiteCommand)cmd, cmd.CommandText, paramList);
if (transaction.Connection.State == ConnectionState.Closed)
transaction.Connection.Open();
int result = cmd.ExecuteNonQuery();
cmd.Dispose();
return result;
}
/// <summary>
/// Executes the non query.
/// </summary>
/// <param name="cmd">CMD.</param>
/// <returns></returns>
public static int ExecuteNonQuery(IDbCommand cmd)
{
if (cmd.Connection.State == ConnectionState.Closed)
cmd.Connection.Open();
int result = cmd.ExecuteNonQuery();
cmd.Connection.Close();
cmd.Dispose();
return result;
}
/// <summary>
/// Shortcut to ExecuteScalar with Sql Statement embedded params and object[] param values
/// </summary>
/// <param name="connectionString">SQLite Connection String</param>
/// <param name="commandText">SQL statment with embedded "@param" style parameters</param>
/// <param name="paramList">object[] array of param values</param>
/// <returns></returns>
public static object ExecuteScalar(string connectionString, string commandText, params object[] paramList)
{
SQLiteConnection cn = new SQLiteConnection(connectionString);
SQLiteCommand cmd = cn.CreateCommand();
cmd.CommandText = commandText;
AttachParameters(cmd, commandText, paramList);
if (cn.State == ConnectionState.Closed)
cn.Open();
object result = cmd.ExecuteScalar();
cmd.Dispose();
cn.Close();
return result;
}
/// <summary>
/// Execute XmlReader with complete Command
/// </summary>
/// <param name="command">SQLite Command</param>
/// <returns>XmlReader</returns>
public static XmlReader ExecuteXmlReader(IDbCommand command)
{ // open the connection if necessary, but make sure we
// know to close it when we�re done.
if (command.Connection.State != ConnectionState.Open)
{
command.Connection.Open();
}
// get a data adapter
SQLiteDataAdapter da = new SQLiteDataAdapter((SQLiteCommand)command);
DataSet ds = new DataSet();
// fill the data set, and return the schema information
da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
da.Fill(ds);
// convert our dataset to XML
StringReader stream = new StringReader(ds.GetXml());
command.Connection.Close();
// convert our stream of text to an XmlReader
return new XmlTextReader(stream);
}
/// <summary>
/// Parses parameter names from SQL Statement, assigns values from object array , /// and returns fully populated ParameterCollection.
/// </summary>
/// <param name="commandText">Sql Statement with "@param" style embedded parameters</param>
/// <param name="paramList">object[] array of parameter values</param>
/// <returns>SQLiteParameterCollection</returns>
/// <remarks>Status experimental. Regex appears to be handling most issues. Note that parameter object array must be in same ///order as parameter names appear in SQL statement.</remarks>
private static SQLiteParameterCollection AttachParameters(SQLiteCommand cmd, string commandText, params object[] paramList)
{
if (paramList == null || paramList.Length == 0) return null;
SQLiteParameterCollection coll = cmd.Parameters;
string parmString = commandText.Substring(commandText.IndexOf("@"));
// pre-process the string so always at least 1 space after a comma.
parmString = parmString.Replace(",", " ,");
// get the named parameters into a match collection
string pattern = @"(@)\S*(.*?)\b";
Regex ex = new Regex(pattern, RegexOptions.IgnoreCase);
MatchCollection mc = ex.Matches(parmString);
string[] paramNames = new string[mc.Count];
int i = 0;
foreach (Match m in mc)
{
paramNames[i] = m.Value;
i++;
}
// now let's type the parameters
int j = 0;
Type t = null;
foreach (object o in paramList)
{
t = o.GetType();
SQLiteParameter parm = new SQLiteParameter();
switch (t.ToString())
{
case ("DBNull"):
case ("Char"):
case ("SByte"):
case ("UInt16"):
case ("UInt32"):
case ("UInt64"):
throw new SystemException("Invalid data type");
case ("System.String"):
parm.DbType = DbType.String;
parm.ParameterName = paramNames[j];
parm.Value = (string)paramList[j];
coll.Add(parm);
break;
case ("System.Byte[]"):
parm.DbType = DbType.Binary;
parm.ParameterName = paramNames[j];
parm.Value = (byte[])paramList[j];
coll.Add(parm);
break;
case ("System.Int32"):
parm.DbType = DbType.Int32;
parm.ParameterName = paramNames[j];
parm.Value = (int)paramList[j];
coll.Add(parm);
break;
case ("System.Boolean"):
parm.DbType = DbType.Boolean;
parm.ParameterName = paramNames[j];
parm.Value = (bool)paramList[j];
coll.Add(parm);
break;
case ("System.DateTime"):
parm.DbType = DbType.DateTime;
parm.ParameterName = paramNames[j];
parm.Value = Convert.ToDateTime(paramList[j]);
coll.Add(parm);
break;
case ("System.Double"):
parm.DbType = DbType.Double;
parm.ParameterName = paramNames[j];
parm.Value = Convert.ToDouble(paramList[j]);
coll.Add(parm);
break;
case ("System.Decimal"):
parm.DbType = DbType.Decimal;
parm.ParameterName = paramNames[j];
parm.Value = Convert.ToDecimal(paramList[j]);
break;
case ("System.Guid"):
parm.DbType = DbType.Guid;
parm.ParameterName = paramNames[j];
parm.Value = (System.Guid)(paramList[j]);
break;
case ("System.Object"):
parm.DbType = DbType.Object;
parm.ParameterName = paramNames[j];
parm.Value = paramList[j];
coll.Add(parm);
break;
default:
throw new SystemException("Value is of unknown data type");
} // end switch
j++;
}
return coll;
}
/// <summary>
/// Executes non query typed params from a DataRow
/// </summary>
/// <param name="command">Command.</param>
/// <param name="dataRow">Data row.</param>
/// <returns>Integer result code</returns>
public static int ExecuteNonQueryTypedParams(IDbCommand command, DataRow dataRow)
{
int retVal = 0;
// If the row has values, the store procedure parameters must be initialized
if (dataRow != null && dataRow.ItemArray.Length > 0)
{
// Set the parameters values
AssignParameterValues(command.Parameters, dataRow);
retVal = ExecuteNonQuery(command);
}
else
{
retVal = ExecuteNonQuery(command);
}
return retVal;
}
/// <summary>
/// This method assigns dataRow column values to an IDataParameterCollection
/// </summary>
/// <param name="commandParameters">The IDataParameterCollection to be assigned values</param>
/// <param name="dataRow">The dataRow used to hold the command's parameter values</param>
/// <exception cref="System.InvalidOperationException">Thrown if any of the parameter names are invalid.</exception>
protected internal static void AssignParameterValues(IDataParameterCollection commandParameters, DataRow dataRow)
{
if (commandParameters == null || dataRow == null)
{
// Do nothing if we get no data
return;
}
DataColumnCollection columns = dataRow.Table.Columns;
int i = 0;
// Set the parameters values
foreach (IDataParameter commandParameter in commandParameters)
{
// Check the parameter name
if (commandParameter.ParameterName == null ||
commandParameter.ParameterName.Length <= 1)
throw new InvalidOperationException(string.Format(
"Please provide a valid parameter name on the parameter #{0}, the ParameterName property has the following value: '{1}'.",
i, commandParameter.ParameterName));
if (columns.Contains(commandParameter.ParameterName))
commandParameter.Value = dataRow[commandParameter.ParameterName];
else if (columns.Contains(commandParameter.ParameterName.Substring(1)))
commandParameter.Value = dataRow[commandParameter.ParameterName.Substring(1)];
i++;
}
}
/// <summary>
/// This method assigns dataRow column values to an array of IDataParameters
/// </summary>
/// <param name="commandParameters">Array of IDataParameters to be assigned values</param>
/// <param name="dataRow">The dataRow used to hold the stored procedure's parameter values</param>
/// <exception cref="System.InvalidOperationException">Thrown if any of the parameter names are invalid.</exception>
protected void AssignParameterValues(IDataParameter[] commandParameters, DataRow dataRow)
{
if ((commandParameters == null) || (dataRow == null))
{
// Do nothing if we get no data
return;
}
DataColumnCollection columns = dataRow.Table.Columns;
int i = 0;
// Set the parameters values
foreach (IDataParameter commandParameter in commandParameters)
{
// Check the parameter name
if (commandParameter.ParameterName == null ||
commandParameter.ParameterName.Length <= 1)
throw new InvalidOperationException(string.Format(
"Please provide a valid parameter name on the parameter #{0}, the ParameterName property has the following value: '{1}'.",
i, commandParameter.ParameterName));
if (columns.Contains(commandParameter.ParameterName))
commandParameter.Value = dataRow[commandParameter.ParameterName];
else if (columns.Contains(commandParameter.ParameterName.Substring(1)))
commandParameter.Value = dataRow[commandParameter.ParameterName.Substring(1)];
i++;
}
}
/// <summary>
/// This method assigns an array of values to an array of IDataParameters
/// </summary>
/// <param name="commandParameters">Array of IDataParameters to be assigned values</param>
/// <param name="parameterValues">Array of objects holding the values to be assigned</param>
/// <exception cref="System.ArgumentException">Thrown if an incorrect number of parameters are passed.</exception>
protected void AssignParameterValues(IDataParameter[] commandParameters, params object[] parameterValues)
{
if ((commandParameters == null) || (parameterValues == null))
{
// Do nothing if we get no data
return;
}
// We must have the same number of values as we pave parameters to put them in
if (commandParameters.Length != parameterValues.Length)
{
throw new ArgumentException("Parameter count does not match Parameter Value count.");
}
// Iterate through the IDataParameters, assigning the values from the corresponding position in the
// value array
for (int i = 0, j = commandParameters.Length, k = 0; i < j; i++)
{
if (commandParameters[i].Direction != ParameterDirection.ReturnValue)
{
// If the current array value derives from IDataParameter, then assign its Value property
if (parameterValues[k] is IDataParameter)
{
IDataParameter paramInstance;
paramInstance = (IDataParameter)parameterValues[k];
if (paramInstance.Direction == ParameterDirection.ReturnValue)
{
paramInstance = (IDataParameter)parameterValues[++k];
}
if (paramInstance.Value == null)
{
commandParameters[i].Value = DBNull.Value;
}
else
{
commandParameters[i].Value = paramInstance.Value;
}
}
else if (parameterValues[k] == null)
{
commandParameters[i].Value = DBNull.Value;
}
else
{
commandParameters[i].Value = parameterValues[k];
}
k++;
}
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data.SqlClient;
namespace GitNotifyCommon
{
/// <summary>
/// Author : yenange
/// Date : 2014-02-21
/// Description: 日志辅助类
/// </summary>
public sealed class Logger
{
#region [ 单例模式 ]
private static readonly Logger _logger = new Logger();
private static readonly log4net.ILog _Logger4net = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// 无参私有构造函数
/// </summary>
private Logger()
{
}
/// <summary>
/// 得到单例
/// </summary>
public static Logger Singleton
{
get
{
return _logger;
}
}
#endregion
#region [ 参数 ]
public bool IsDebugEnabled
{
get { return _Logger4net.IsDebugEnabled; }
}
public bool IsInfoEnabled
{
get { return _Logger4net.IsInfoEnabled; }
}
public bool IsWarnEnabled
{
get { return _Logger4net.IsWarnEnabled; }
}
public bool IsErrorEnabled
{
get { return _Logger4net.IsErrorEnabled; }
}
public bool IsFatalEnabled
{
get { return _Logger4net.IsFatalEnabled; }
}
#endregion
#region [ 接口方法 ]
#region [ Debug ]
#region [ 不带dbId ]
public void Debug(string message)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, message);
}
}
public void Debug(string message, Exception exception)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, message, exception);
}
}
public void DebugFormat(string format, params object[] args)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, format, args);
}
}
public void DebugFormat(string format, Exception exception, params object[] args)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, string.Format(format, args), exception);
}
}
#endregion
#region [ 带dbId ]
public void DebugFormat2(long dbId, string message)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, string.Format("dbId:{0}, {1}", dbId, message));
}
}
public void DebugFormat2(long dbId, string message, Exception exception)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, string.Format("dbId:{0}, {1}", message), exception);
}
}
public void DebugFormat2(long dbId, string format, params object[] args)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)));
}
}
public void DebugFormat2(long dbId, string format, Exception exception, params object[] args)
{
if (this.IsDebugEnabled)
{
this.Log(LogLevel.Debug, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)), exception);
}
}
#endregion
#endregion
#region [ Info ]
#region [ 不带dbId ]
public void Info(string message)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, message);
}
}
public void Info(string message, Exception exception)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, message, exception);
}
}
public void InfoFormat(string format, params object[] args)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, format, args);
}
}
public void InfoFormat(string format, Exception exception, params object[] args)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, string.Format(format, args), exception);
}
}
#endregion
#region [ 带dbId ]
public void InfoFormat2(long dbId, string message)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, string.Format("dbId:{0}, {1}", dbId, message));
}
}
public void InfoFormat2(long dbId, string message, Exception exception)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, string.Format("dbId:{0}, {1}", dbId, message), exception);
}
}
public void InfoFormat2(long dbId, string format, params object[] args)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)));
}
}
public void InfoFormat2(long dbId, string format, Exception exception, params object[] args)
{
if (this.IsInfoEnabled)
{
this.Log(LogLevel.Info, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)), exception);
}
}
#endregion
#endregion
#region [ Warn ]
#region [ 不带dbId ]
public void Warn(string message)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, message);
}
}
public void Warn(string message, Exception exception)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, message, exception);
}
}
public void WarnFormat(string format, params object[] args)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, format, args);
}
}
public void WarnFormat(string format, Exception exception, params object[] args)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, string.Format(format, args), exception);
}
}
#endregion
#region [ 带dbId ]
public void WarnFormat2(long dbId, string message)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, string.Format("dbId:{0}, {1}", dbId, message));
}
}
public void WarnFormat2(long dbId, string message, Exception exception)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, string.Format("dbId:{0}, {1}", dbId, message), exception);
}
}
public void WarnFormat2(long dbId, string format, params object[] args)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)));
}
}
public void WarnFormat2(long dbId, string format, Exception exception, params object[] args)
{
if (this.IsWarnEnabled)
{
this.Log(LogLevel.Warn, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)), exception);
}
}
#endregion
#endregion
#region [ Error ]
#region [ 不带dbId ]
public void Error(string message)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, message);
}
}
public void Error(string message, Exception exception)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, message, exception);
}
}
public void ErrorFormat(string format, params object[] args)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, format, args);
}
}
public void ErrorFormat(string format, Exception exception, params object[] args)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, string.Format(format, args), exception);
}
}
#endregion
#region [ 带dbId ]
public void ErrorFormat2(long dbId, string message)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, string.Format("dbId:{0}, {1}", dbId, message));
}
}
public void ErrorFormat2(long dbId, string message, Exception exception)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, string.Format("dbId:{0}, {1}", dbId, message), exception);
}
}
public void ErrorFormat2(long dbId, string format, params object[] args)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)));
}
}
public void ErrorFormat2(long dbId, string format, Exception exception, params object[] args)
{
if (this.IsErrorEnabled)
{
this.Log(LogLevel.Error, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)), exception);
}
}
#endregion
#endregion
#region [ Fatal ]
#region [ 不带dbId ]
public void Fatal(string message)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, message);
SaveExceptionToDB(message, new Exception(message), 0);
}
}
public void Fatal(string message, Exception exception)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, message, exception);
SaveExceptionToDB(message, exception, 0);
}
}
public void FatalFormat(string format, params object[] args)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, format, args);
SaveExceptionToDB(string.Format(format, args), new Exception(string.Format(format, args)), 0);
}
}
public void FatalFormat(string format, Exception exception, params object[] args)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, string.Format(format, args), exception);
SaveExceptionToDB(string.Format(format, args), exception, 0);
}
}
#endregion
#region [ 带dbId ]
public void FatalFormat2(long dbId, string message)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, string.Format("dbId:{0}, {1}", dbId, message));
SaveExceptionToDB(message, new Exception(message), dbId);
}
}
public void FatalFormat2(long dbId,string message, Exception exception)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, string.Format("dbId:{0}, {1}", dbId, message), exception);
SaveExceptionToDB(message, exception, dbId);
}
}
public void FatalFormat2(long dbId, string format, params object[] args)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)) );
SaveExceptionToDB(string.Format(format, args), new Exception(string.Format(format, args)), dbId);
}
}
public void FatalFormat2(long dbId, string format, Exception exception, params object[] args)
{
if (this.IsFatalEnabled)
{
this.Log(LogLevel.Fatal, string.Format("dbId:{0}, {1}", dbId, string.Format(format, args)), exception);
SaveExceptionToDB(string.Format(format, args), exception, dbId);
}
}
#endregion
#endregion
/// <summary>
/// 输出到 ErrorLog 表, 便于查找
/// </summary>
/// <param name="message">相关信息</param>
/// <param name="exception">异常对象</param>
/// <param name="dbId">dbId</param>
private void SaveExceptionToDB(string message, Exception exception, long dbId)
{
//无数据库操作
}
#endregion
#region [ 内部方法 ]
/// <summary>
/// 输出普通日志
/// </summary>
/// <param name="level"></param>
/// <param name="format"></param>
/// <param name="args"></param>
private void Log(LogLevel level, string format, params object[] args)
{
switch (level)
{
case LogLevel.Debug:
_Logger4net.DebugFormat(format, args);
break;
case LogLevel.Info:
_Logger4net.InfoFormat(format, args);
break;
case LogLevel.Warn:
_Logger4net.WarnFormat(format, args);
break;
case LogLevel.Error:
_Logger4net.ErrorFormat(format, args);
break;
case LogLevel.Fatal:
_Logger4net.FatalFormat(format, args);
break;
}
}
/// <summary>
/// 格式化输出异常信息
/// </summary>
/// <param name="level"></param>
/// <param name="message"></param>
/// <param name="exception"></param>
private void Log(LogLevel level, string message, Exception exception)
{
switch (level)
{
case LogLevel.Debug:
_Logger4net.Debug(message, exception);
break;
case LogLevel.Info:
_Logger4net.Info(message, exception);
break;
case LogLevel.Warn:
_Logger4net.Warn(message, exception);
break;
case LogLevel.Error:
_Logger4net.Error(message, exception);
break;
case LogLevel.Fatal:
_Logger4net.Fatal(message, exception);
break;
}
}
#endregion
}//end of class
#region [ enum: LogLevel ]
/// <summary>
/// 日志级别
/// </summary>
public enum LogLevel
{
Debug,
Info,
Warn,
Error,
Fatal
}
#endregion
}//end of namespace
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace GitNotifyCommon
{
public static class CommonConfig
{
private static string _SqliteConnString = "no";
/// <summary>
/// Sqlite 连接串
/// </summary>
public static string SqliteConnString
{
get
{
if (_SqliteConnString == "no")
{
string strValue = System.Configuration.ConfigurationManager.AppSettings["SqliteConnString"];
_SqliteConnString = strValue;
}
return _SqliteConnString;
}
}
private static string _LocalGitCmd = "no";
/// <summary>
/// 监控目录
/// </summary>
public static string LocalGitCmd
{
get
{
if(_LocalGitCmd=="no")
{
string strValue = System.Configuration.ConfigurationManager.AppSettings["LocalGitCmd"];
_LocalGitCmd = strValue;
}
return _LocalGitCmd;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
namespace GitNotifyCommon
{
/// <summary>
/// Author : yenange
/// Date : 2014-02-26
/// Description : 邮件发送辅助类
/// </summary>
public class EmailHelper
{
#region [ 属性(发送Email相关) ]
private string _SmtpHost = string.Empty;
//private int _SmtpPort = -1;
private string _FromEmailAddress = string.Empty;
private string _FormEmailPassword = string.Empty;
/// <summary>
/// smtp 服务器
/// </summary>
public string SmtpHost
{
get
{
return "smtp.163.com";
}
}
/// <summary>
/// smtp 服务器端口 默认为25
/// </summary>
public int SmtpPort
{
get
{
return 25;
}
}
/// <summary>
/// 发送者 Eamil 地址
/// </summary>
public string FromEmailAddress
{
get
{
return "xxx@163.com";
}
}
/// <summary>
/// 发送者 Eamil 密码
/// </summary>
public string FromEmailPassword
{
get
{
return "xxxx";
}
}
#endregion
#region [ 属性(邮件相关) ]
/// <summary>
/// 收件人 Email 列表,多个邮件地址之间用 半角逗号 分开
/// </summary>
public string ToList { get; set; }
/// <summary>
/// 邮件的抄送者,支持群发,多个邮件地址之间用 半角逗号 分开
/// </summary>
public string CCList { get; set; }
/// <summary>
/// 邮件的密送者,支持群发,多个邮件地址之间用 半角逗号 分开
/// </summary>
public string BccList { get; set; }
/// <summary>
/// 邮件标题
/// </summary>
public string Subject { get; set; }
/// <summary>
/// 邮件正文
/// </summary>
public string Body { get; set; }
private bool _IsBodyHtml = true;
/// <summary>
/// 邮件正文是否为Html格式
/// </summary>
public bool IsBodyHtml
{
get { return _IsBodyHtml; }
set { _IsBodyHtml = value; }
}
/// <summary>
/// 附件列表
/// </summary>
public List<Attachment> AttachmentList { get; set; }
#endregion
#region [ 构造函数 ]
public EmailHelper() { }
/// <summary>
/// 构造函数 (body默认为html格式)
/// </summary>
/// <param name="toList">收件人列表</param>
/// <param name="subject">邮件标题</param>
/// <param name="body">邮件正文</param>
public EmailHelper(string toList, string subject, string body)
{
this.ToList = toList;
this.Subject = subject;
this.Body = body;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="toList">收件人列表</param>
/// <param name="subject">邮件标题</param>
/// <param name="isBodyHtml">邮件正文是否为Html格式</param>
/// <param name="body">邮件正文</param>
public EmailHelper(string toList, string subject, bool isBodyHtml, string body)
{
this.ToList = toList;
this.Subject = subject;
this.IsBodyHtml = isBodyHtml;
this.Body = body;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="toList">收件人列表</param>
/// <param name="ccList">收件人列表</param>
/// <param name="subject">邮件标题</param>
/// <param name="isBodyHtml">邮件正文是否为Html格式</param>
/// <param name="body">邮件正文</param>
public EmailHelper(string toList, string ccList, string subject, bool isBodyHtml, string body)
{
this.ToList = toList;
this.CCList = ccList;
this.Subject = subject;
this.IsBodyHtml = isBodyHtml;
this.Body = body;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="toList">收件人列表</param>
/// <param name="ccList">抄送人列表</param>
/// <param name="bccList">密送人列表</param>
/// <param name="subject">邮件标题</param>
/// <param name="isBodyHtml">邮件正文是否为Html格式</param>
/// <param name="body">邮件正文</param>
public EmailHelper(string toList, string ccList, string bccList, string subject, bool isBodyHtml, string body)
{
this.ToList = toList;
this.CCList = ccList;
this.BccList = bccList;
this.Subject = subject;
this.IsBodyHtml = isBodyHtml;
this.Body = body;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="toList">收件人列表</param>
/// <param name="ccList">抄送人列表</param>
/// <param name="bccList">密送人列表</param>
/// <param name="subject">邮件标题</param>
/// <param name="isBodyHtml">邮件正文是否为Html格式</param>
/// <param name="body">邮件正文</param>
/// <param name="attachmentList">附件列表</param>
public EmailHelper(string toList, string ccList, string bccList, string subject, bool isBodyHtml, string body, List<Attachment> attachmentList)
{
this.ToList = toList;
this.CCList = ccList;
this.BccList = bccList;
this.Subject = subject;
this.IsBodyHtml = isBodyHtml;
this.Body = body;
this.AttachmentList = attachmentList;
}
#endregion
#region [ 发送邮件 ]
/// <summary>
/// 发送邮件
/// </summary>
/// <returns></returns>
public void Send()
{
SmtpClient smtp = new SmtpClient(); //实例化一个SmtpClient
smtp.DeliveryMethod = SmtpDeliveryMethod.Network; //将smtp的出站方式设为 Network
smtp.EnableSsl = false; //smtp服务器是否启用SSL加密
smtp.Host = this.SmtpHost; //指定 smtp 服务器地址
smtp.Port = this.SmtpPort; //指定 smtp 服务器的端口,默认是25,如果采用默认端口,可省去
smtp.UseDefaultCredentials = true; //如果你的SMTP服务器不需要身份认证,则使用下面的方式,不过,目前基本没有不需要认证的了
smtp.Credentials = new NetworkCredential(this.FromEmailAddress, this.FromEmailPassword); //如果需要认证,则用下面的方式
MailMessage mm = new MailMessage(); //实例化一个邮件类
mm.Priority = MailPriority.Normal; //邮件的优先级,分为 Low, Normal, High,通常用 Normal即可
mm.From = new MailAddress(this.FromEmailAddress, "管理员", Encoding.GetEncoding(936));
//收件人
if (!string.IsNullOrEmpty(this.ToList))
mm.To.Add(this.ToList);
//抄送人
if (!string.IsNullOrEmpty(this.CCList))
mm.CC.Add(this.CCList);
//密送人
if (!string.IsNullOrEmpty(this.BccList))
mm.Bcc.Add(this.BccList);
mm.Subject = this.Subject; //邮件标题
mm.SubjectEncoding = Encoding.GetEncoding(936); //这里非常重要,如果你的邮件标题包含中文,这里一定要指定,否则对方收到的极有可能是乱码。
mm.IsBodyHtml = this.IsBodyHtml; //邮件正文是否是HTML格式
mm.BodyEncoding = Encoding.GetEncoding(936); //邮件正文的编码, 设置不正确, 接收者会收到乱码
mm.Body = this.Body; //邮件正文
//邮件附件
if (this.AttachmentList != null && this.AttachmentList.Count > 0)
{
foreach (Attachment attachment in this.AttachmentList)
{
mm.Attachments.Add(attachment);
}
}
//发送邮件,如果不返回异常, 则大功告成了。
smtp.Send(mm);
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GitNotifyCommon.Model;
using System.Data;
namespace GitNotifyCommon.DAL
{
public class ProjectDAL
{
public static List<Project> GetList()
{
List<Project> list = new List<Project>();
string sql = "SELECT * from project_data where isEnabled=1";
DataTable dt = SQLiteHelper.ExecuteDataSet(CommonConfig.SqliteConnString, sql, null).Tables[0];
foreach (DataRow dr in dt.Rows)
{
list.Add(GetModel(dr));
}
return list;
}
public static Project GetModel(DataRow dr)
{
Project item = new Project()
{
ProjectId = Convert.ToInt32(dr["projectId"]),
ProjectName = Convert.ToString(dr["projectName"]),
LocalPath = Convert.ToString(dr["localPath"]),
LastUpdateTime = Convert.ToDateTime(dr["lastUpdateTime"]),
LastLog = Convert.ToString(dr["lastLog"]),
EmailToList = Convert.ToString(dr["emailToList"]),
IsEnabled = Convert.ToBoolean(dr["isEnabled"])
};
return item;
}
public static void Update(Project item)
{
string sql = "update project_data set lastUpdateTime=@lastUpdateTime,lastLog=@lastLog where projectId=@projectId";
object[] arr = { item.LastUpdateTime, item.LastLog, item.ProjectId };
SQLiteHelper.ExecuteNonQuery(CommonConfig.SqliteConnString,sql,arr);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GitNotifyCommon.Model
{
public class Project
{
public int ProjectId { get; set; }
public string ProjectName { get; set; }
public string LocalPath { get; set; }
public DateTime LastUpdateTime { get; set; }
public string LastLog { get; set; }
public string EmailToList { get; set; }
public bool IsEnabled { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FileWatcherCommon;
namespace GitNotify
{
class Program
{
static void Main(string[] args)
{
WatcherGit.Run();
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- Sqlite连接串 -->
<add key="SqliteConnString" value="Data Source=gitInfo.sqlite3;Version=3;Cache Size=2000;Pooling=True;Max Pool Size=5;" />
<!-- 本地 Git-cmd.exe 完整路径 -->
<add key="LocalGitCmd" value="C:\Program Files\Git\bin\git.exe" />
</appSettings>
</configuration>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>
<!-- 异常输出 -->
<appender name="FatalLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Log\" />
<rollingStyle value="Composite" />
<datePattern value='yyyy-MM-dd".log"' />
<staticLogFileName value="false" />
<maximumFileSize value="30MB" />
<countDirection value="-1" />
<maxSizeRollBackups value="-1" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<header value="-----------程序开始运行----------- " />
<footer value="-----------程序结束运行----------- " />
<conversionPattern value="%date [%thread] %-5level [%ndc] - %message%newline" />
</layout>
</appender>
<root>
<level value="INFO" />
<appender-ref ref="FatalLogFileAppender" />
</root>
</log4net>
</configuration>