VSTS(旧VSOnline)にコマンドを投げれなくてはまった(2)

Basic認証を許可すればコマンドからGitリポジトリにアクセスできることはわかりました。 また、PSスクリプトからコマンドを投げる(実際にはgit.exeのプロセスを起動)際にも問題がありそうだということも分かりました。

スクリプトからの呼び出しについては、実は大体原因が分かっていて、コマンドラインから自分でコマンドを実行してみると途中でユーザ名・パスワードを聞かれるのと同じことが起きているものの、スクリプト内では単純にプロセスを起動しているだけなので、標準入力で待ちの状態になっていると思われます。なので、然るべき処理を追加してユーザ名とパスワードを流し込んでやれば多分実行できます。

しかし、そもそも論というか、HTTPSとはいえ今どきBasic認証ってどうなん・・?という疑問も残ります。ふと、そんなことを思っていたところ、きよくらさんよりありがたい啓示が。

要はVSTSにおける認証を管理してくれるアプリケーションみたいです。

Git-Credential-Manager-for-Windows - GitHub

こいつをインストールした後に、先ほどと同じようにコマンドラインからGitプルとかすると、今度はBasic認証ではなく、新しいウィンドウが開いてMSアカウントでの認証ができるようになり・・・ませんでした(T-T)

どうやら、私の環境では設定が正しく更新されなかったようで、FAQ を参考に credential.helper をセットし、もう一度コマンドを投げることでようやくMSアカウントでの認証となりました。

git config credential.helper manager

ちなみに、コマンドから手動で credential.helper を設定した場合、PCを再起動するともう一度設定し直す必要があるようなので、頻繁に利用する場合は.gitconfig とかを弄る必要がありそうです (未確認)

追記

C:\Users\<ユーザ> フォルダ直下にある .gitconfig に設定を追加すればよいようです。

[credential]
    helper = manager

VSTS(旧VSOnline)にコマンドを投げれなくてはまった(1)

普段、チームエクスプローラや外部アプリだとSourceTreeなどでGitリポジトリにアクセスしているので気にしていなかったのですが、ビルドの手順を自動化しようと思いPSスクリプトを書いて、「えいやっ!」と投げつけるとGitプルで停止して先へ進まなくなる、という現象に遭遇しました。

ちなみにスクリプトからではなく、コマンドラインから「git pull origin master」とかすると、ユーザ名とパスワードを聞かれますが、ログインに使用しているはずのMSアカウントのユーザ名とパスワードでは認証に失敗します。

この問題、Githubにおいているリポジトリだと再現せずに気が付くのが遅れたので、覚書程度に書き出しておきます。

といっても、結論を言ってしまうと、コマンドラインからVSTS(旧VSOnline)のGitに対してリクエストを投げる際には、予めBasic認証を有効にしておく必要がある、ということらしいです。

Git コマンド プロンプトからの作業 - MSDN

アップデートによって画面構成が若干変わっていますが、VSTSにログインして「My Profile」を選択し”Security”タブをクリック。

サブメニューの ''Alternate authentication credentials'' を選択して、”Enable alternate authentication credentials” にチェックを入れて、認証で使うユーザ名とパスワードを入力して保存します。

そうするとコマンド実行時に、先ほど設定したBasic認証用のユーザ名とパスワードを入力することで、認証が通るようになります。

が、PSスクリプトの方は相変わらず途中で停止してしまうという問題が・・・(続く)

サーバ側だけに存在するオブジェクトを無視して DB を更新する

すべてをDBプロジェクトを起点にして開発されていれば、先ほどのように無条件に更新で良いのですが、(大人の事情で)サーバ側には存在するけど、DBプロジェクトではあえて管理していないオブジェクトがあったりします。

そんなオブジェクトが存在する場合、前回のデプロイを無条件に実行するとソースに無いオブジェクトはがっつり削除されてしまいます・・。デプロイするたびに削除され、それをまた手動で作り直したのでは効率が悪いので、とりあえず無視する設定を足しておきましょう。

DropObjectsNotInSource="false"

ちなみに、手動で実行する場合は、SSDTのスキーマ比較オプションから"ソース内にないオブジェクトを削除する"をOFFに変更して、更新を実行すると同じ効果のようです。

追記

SqlSchemaCompareTask - MSDN を見ても各プロパティの説明は一切なくて諦めかけていたのだけど、よく見るとスキーマ比較のオプションで項目を選択すると、下側に日本語の説明が表示されてます。ざっと眺めた感じ、プロパティと対応するオプションが一通りそろっているようなので、こっちを参考にするとよいです、きっと。

MSBuild から DB を更新する

SSDTSQL Server Data Tools)を使うと、DBプロジェクトで管理しているオブジェクトと、サーバ側のオブジェクトとを比較して、差分のみを適用することができます。

これはこれで便利なのですが、手動で毎度ポチポチ操作して更新するのが面倒なので、自動化を考えてみました。

基本的には、"スキーマ比較"→"対象のDB選択"→"比較"→"更新"の順に操作しているだけなので、これをMSBuildのタスクとして登録します。

<Target Name="myDeploy">
  <SqlSchemaCompareTask
    source="$(OutputPath)\$(ProjectName).dacpac"
    target="(接続文字列)"
    Deploy="true" />
</Target>
プロパティ
source 比較元
target 比較先
Deploy targetにデプロイするかどうか

最小構成だとこんな感じでしょうか?これをプロジェクトファイル(.sqlproj)に追記して、コマンドからこんな感じでmsbuildを実行するとデプロイされます。

msbuild /t:Build;myDeploy

より詳しい情報は、MSDN Blogの記事 を参考にするといいと思います。

Gitで管理されているファイルの変更を無視する方法

チーム開発をしている場合、設定ファイルに書かれているデータベースの接続情報など、全員が同じ設定を利用できるのであれば問題はありません。 しかし、ローカルDBを使ったり、しばらく別のDBに接続して開発するなんてことも間々あると思います。

短期間であれば作業してコミット前に変更を取り消せばよいだけで(ひと手間ありますが)特に困りません。ただ、途中で最新のソースが欲しくなってマージを実行したりすると、その度にコンフリクトが発生してイラッ☆とします。

そんな時は、対象の設定ファイルをGitの管理対象から一時的に外してしまうとよいです。方法は以下のようにGitのコマンドを実行します。

git update-index --assume-unchanged src/WebApplication1/Web.config

これで、ローカルの変更は無視されるようになります。

もし、(設定が増えるなどで)対象のファイルが更新された場合、今度は除外を解除してから取り込み、その後また管理対象から外してしまいます。

git update-index --no-assume-unchanged src/WebApplication1/Web.config

余談

VS2013で開発していると、除外していても(時々ですが)ブランチを切り替えようとした時になぜか変更を検知して切り替えれないといった現象を確認しています。 ※例えば、トピックブランチで作業が終わったから、リリースブランチに切り替えて別の検証をしようとしたときなど

色々試してみたものの、うまく回避できる方法がなかったので、リリースブランチ、デベロップブランチは別々にチェックアウトするようにしています。

CSVHelper でカンマ区切りの数値を読ませる

お仕事で使っていてはまったのでメモ。

お題としては、普通のCSVではなくてTSV(タブ区切り)形式のファイルを読み込むというもので、その中の項目のひとつに数値(3桁カンマ区切り)が含まれている、というもの。

で、サンプルを参考にしながら組んでいったわけですが、デフォルトのままだとマッピング時に例外が発生してしまいます。

型 'CsvHelper.TypeConversion.CsvTypeConverterException' のハンドルされていない例外が CsvHelper.dll で発生しました 追加情報:The conversion cannot be performed.

コンバーターが対応していないのならと、いそいそとCustomTypeConverterを書いていたのですが、本家のソースを眺めていると、もっと簡単に以下のオプションをマッピングの定義に追加指定するだけで良いことに気が付きました。

Map(m => m.column3).Index(2).TypeConverterOption(NumberStyles.Number);

ちなみに今回のケースだと、上記のオプションではなく DecimalConverter を明示的に指定することでも読み込むことができます。じゃあ、なぜそちらを使わなかったかというと、空値を読めなかったから。

お題には書き忘れてましたが、値として空白もありうるという難題でした・・。

パッケージにはNull許可のDecimal用のコンバータは用意されておらず、代わりに(?) NullableConverter というコンバータがあるのですが、これだとカンマ区切りの数値には対応していないという(^^;;

まぁ、コンバーターの詳細は この辺 を読んでもらうことにして、最後に確認用に書いたコードを貼り付けておきます。

class Program
{
  static void Main(string[] args)
  {
    var lines =
      "column1\tcolumn2\tcolumn3\r\n" +
      "hoge\t1000\t1,000\r\n";

    using (var sr = new StringReader(lines))
    {
      using (var cr = new CsvReader(sr))
      {
        cr.Configuration.Delimiter = "\t";
        cr.Configuration.RegisterClassMap<DataClassMap>();

        var records = cr.GetRecords<Data>();

        foreach (var record in records)
        {
          Console.WriteLine("{0},{1},{2}", record.column1, record.column2, record.column3);
        }
      }
    }
  }
}

class Data
{
  public string column1 { get; set; }
  public int column2 { get; set; }
  public decimal column3 { get; set; }
}

class DataClassMap : CsvClassMap<Data>
{
  public DataClassMap()
  {
    Map(m => m.column1).Index(0);
    Map(m => m.column2).Index(1);
    Map(m => m.column3).Index(2).TypeConverterOption(NumberStyles.Number);
  }
}

SQL Serverの照合順序ではまった

SSDTを使うようになって、ストアドプロシージャの単体テストなんかもVS2013で作れて非常に便利に使っていたのですが、なぜか一時テーブルを使っていたストアドのテストが通らずかなり悩みました・・。

いろいろと試行錯誤した結果、データベースプロジェクトが作ってくれるテストは標準ではLocalDBに対して環境を構築し、単体テストを実行する流れになっているのですが、このLocalDBの照合順序とテスト対象のデータベースの照合順序と異なるためにエラーになるようです。

SQL Server 2014 Express LocalDB - MSDN

LocalDB のインスタンスの照合順序は SQL_Latin1_General_CP1_CI_AS に設定され、変更することはできません。 データベース レベル、列レベル、および式レベルの照合順序は正常にサポートされます。

LocalDBはインスタンスレベルで固定となっていて、masterやtempなどもその設定となるようで変更することはできないようです・・。

仕方がないので、ひとまずはLocalDBをやめて普通のSQL Serverインスタンスに配置するよう設定を切り替えて逃げたんですが、頑張ればどうにかなるものなのかな?