📝

Copilot Workspaceでメール内容の更新を試してみた

2024/12/21に公開

READYFORプロダクトエンジニアの森です。

続々とCopilot関連サービスがリリースされる中、今年の4月に「GitHub Copilot Workspace」の発表がありました。
本記事を公開する2024年12月21日時点では、まだTechnical Previewのためwaitlistの登録が必要になっています。
https://githubnext.com/projects/copilot-workspace/

他の方が投稿されている記事を眺めたり自分でも少しだけ触ってみたところでは、大きなものを丸投げ(「RailsでToDoアプリを作って!」のようなレベル)するには難しいけれど、ちょっとした変更であれば多少雑に投げてもどうにかしてくれそうな感覚があります。
ちょっとした変更のPull Requestを作成できるレベルまでできるのであれば、非エンジニアでも変更できる範囲が広がるのでは?というところから、仮に正式リリースされた場合、実際に活用しようとすると、どういったことができる可能性があるか、メールの変更を題材にして試してみました。

前提条件

「非エンジニアでも変更できる範囲が広がるのでは?」というところが発端のため、ガッツリとした開発ではなくちょっとした文言変更を対象にしています。
また、Issueの内容も、メソッド名を出したり具体的にモデルを指定するといったことはしないようにしています。

今回は検証用のため、個人のリポジトリを使用しました。

  • 変更を加えたいリポジトリ: rails8_blog_sample

rails8_blog_sampleは、簡易的なブログっぽいものを投稿・編集する画面、投稿された内容の一覧や詳細を表示する画面のみ持っています。
検証用に複数のメール送信処理を入れたかったため、新規投稿と更新が完了したタイミングで、ActionMailerを利用してメールを飛ばすようにしています。

初期のModel,Controller,Mailerの状態
# app/models/post.rb
class Post < ApplicationRecord
  # title     :string
  # body      :string
  # posted_at :datetime
end

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  # index,show,new,editは省略
  def create
    @post = Post.new(post_params)

    if @post.save
      PostMailer.new_post(@post).deliver
      redirect_to @post
    else
      render :new
    end
  end

  def update
    @post = Post.find(params[:id])

    if @post.update(post_params)
      PostMailer.update_post(@post).deliver
      redirect_to @post
    else
      render :edit
    end
  end

  private

  def post_params
    params.expect(post: [ :title, :body, :posted_at ])
  end
end

# app/mailers/post_mailer.rb
class PostMailer < ApplicationMailer
  def new_post(post)
    @post = post

    mail to: "to@example.org", subject: "新規投稿しました"
  end

  def update_post(post)
    @post = post

    mail to: "to@example.org", subject: "投稿を編集しました"
  end
end

メール本文変更チャレンジ

簡単なメール本文の変更

元のメールは下記のようになっていて、HTMLメールとTEXTメールのテンプレートが存在します。
(冷静に考えて実際これぐらいの文面で送っていることないな…と思いましたが…検証用なので……)

TO:
to@example.org
件名:
新規投稿しました
本文:
Post#new_post

「<%= @post.title %>」を投稿しました。

rails8_blog_sampleに作成されたIssueをCopilot Workspaceで開くと、Issueの内容(キャプチャ左側)を元に、課題とそれに対する解決方法を挙げてくれます(キャプチャ右側)。
Brainstormの結果
試しにそのままの内容でコードを生成してみました。
Plan通りにコードを変更

なかなか良い感じになっています。

  • 複数あるメールのうち、ファイルやメソッドを指定せずとも意図した通りに新規投稿時のメールを更新している
  • HTMLメールとTEXTメール両方のテンプレートを更新している
  • 変数にしたいところは変数になっている
  • 完全に忘れていたテストも更新している

ですが、HTMLメールからタグがなくなっているので、「HTMLメールはタグで囲うこと」をIssueに追記して、再度コードを生成します。
再生成後のコード
リンクのところはlink_toを利用してほしかったところですが、タグに関しては指示した通りに追加されました。

複数レコードの参照があるメールの変更

前の変更を取り込んでいるため、この時点でのメールの内容は下記のようになっています。

TO:
to@example.org
件名:
新規投稿しました
本文:
「<%= @post.title %>」の投稿が完了しました!

こちらから確認可能です
<%= post_url(@post) %>

この文面では@postの参照のみですが、ユーザ宛のメールなどで本文の先頭にユーザ名が含まれることや、メール本文に複数の変数が含まれることもよくあります。
参照するレコードが1つだけの状態なので、複数レコードの参照が必要なケースを考えるため、nameカラムを持ったauthorsテーブルと、それに対応するAuthorモデルを追加し、Postと1:多の関連を持たせました。よくある「投稿」と「投稿者」の関係です。

class Post < ApplicationRecord
  belongs_to :author
end

class Author < ApplicationRecord
  # name :string

  has_many :posts, dependent: :destroy
end

この状態で、本文の先頭に投稿者名を含めるIssueを作成し、Copilot Workspaceで課題と解決策を考えてもらいます。
Subjectの変更も計画に含まれる
パッと見は問題なさそうでしたが、赤い下線を引いた箇所が、特に指示をしていない件名にも投稿者名を入れるような変更になっています。
今回は特にその意図はなかったので、「件名は変更しない」と言う内容を追加して更新すると、指示通りの結果になりました。
Planに「Subjectの変更はしない」が取り込まれた

こうして生成した内容がこちら。
コード生成結果
Mailerのメソッド内に定義した変数は使わないのかい、という気になりポイントはありますが、特にモデル間の関連を指示していない状態でもpostからauthorの参照も問題なくできていました。

本文含む複数箇所の変更

簡単な文章の変更や変数を扱う変更も特に引っかかるところがなさそうなので、1Issueで複数の変更を指示してみます。
また、実際に送信するメールの本文はもっと長いことが多いので、長めの文章に更新しました(ありがとうChatGPT)

TO:
to@example.org
件名:
新しい投稿が公開されました!
本文:

<%= @post.author.name %> 様

こんにちは!いつもサンプル記事投稿サービスをご利用いただき、ありがとうございます。

先ほど、新しい投稿が正常に公開されましたのでお知らせいたします。
ご投稿いただいた内容は、以下のリンクからご確認いただけます。
▼投稿を確認する
タイトル: <%= @post.title %>
<%= post_url(@post) %>

この投稿が、多くの方に届き、素敵な反応をいただけることを願っています!
また、フィードバックが寄せられた際には、[ダッシュボード/お知らせ欄]でご確認いただけますので、ぜひチェックしてみてくださいね。
もし操作方法やご不明点がございましたら、いつでもお気軽にお問い合わせください。
サンプル記事投稿サービスでは、ユーザーの皆様に快適にご利用いただけるよう、引き続きサポートしてまいります。
今後ともサンプル記事投稿サービスをよろしくお願いいたします!
<%= render "footer" %>

footerの内容はこちらで、partial化されている内容への変更を確認するためにあえてpartialにしています。

------
hoge株式会社
hoge県piyo区fuga町 sampleビル 2F
連絡先: xxx-xxxx-xxxx
------

その文章の一部を更新することも含め、いくつかの変更点を箇条書きで指定しました。
いくつかの変更を含むIssueとそのBrainstorm結果
今回も特に違和感がある箇所はなかったので、そのままコードを生成します。
あっさりコードに反映された

何かしらIssueの内容を書き足す必要が出てくるかなと思ったのですが、全く触ることなく意図した結果になりました。

  • 「「この投稿が」から「ぜひチェックしてみてくださいね。」までの文章を下記の文章に変更する」のように変更したい範囲の文章を全て指定しなくても更新している
  • BCCの追加と件名の変更も問題なし
  • キャプチャに収まりきっていないですが、フッターの変更もちゃんとpartial側を変更している

特に「「この投稿が」から「ぜひチェックしてみてくださいね。」のような書き方でも問題なく変更できるのは意外でした。

感想

実際はもっとメール数も多かったり、送信するタイミングも今回のように単純なものではなかったりするため、Issueのテンプレートなどで工夫する必要はあると思いますが、今回試したような簡単な変更程度であれば、雑な内容でも良い感じに計画を立ててコードに反映してくれてありがたい限りでした。
日本語でもよしなに処理してくれるところもありがたいところ。
メールの文面更新のようなことは、実運用上も他部署からの依頼として発生することがあるため、本文の更新系であれば、変更はCopilot Workspaceにお任せ、あとは必要に応じて手直しとレビュー&確認、という流れも組めるのではと感じます。
正式リリースが楽しみです。

おまけ

READYFORでは、一部画面とAPIは別リポジトリになっていたりと、1つの機能を開発する際に複数のリポジトリのコードを変更することがあります。
Issueは一元管理するために1リポジトリで管理しているため、仮にCopilot Workspaceを利用して何かしらの変更を行う場合、Issueがあるリポジトリとは別のリポジトリに対してPull Requestを作成することになります。

今のところ、Copilot WorkspaceではIssueがあるリポジトリとは別のリポジトリに対してPull Requestを作成することができないようなので、解決策の1つとして、Issueに特定のラベルを付与した際にActionsのworkflowが動くようにし、変更を加えるリポジトリへ同じ内容のIssueを作成してリンクするフローが考えられそうです。
せっかくなので、rails8_blog_sample_issuesリポジトリを作成し、workflowの追加もCopilot Workspaceを使用してみました。

下記のような雑なIssueですが、

良い感じにプランを考えてくれました。
すっかり忘れていたので、「Set github-token as PAT_FOR_SAMPLE」のitemのみ後から追加していますが、それ以外はCopilotが自動生成してくれたものです。

生成されたプランで作られた変更内容がこちら。

バージョンが最新ではなかったりしますが、このworkflowで実際に実行してみた結果がこちら。

  • rails8_blog_sample_issuesのIssue
  • rails8_blog_sampleのIssue

やりたいことはできていそうです。
ほとんど修正することもなかったので、サクッとworkflowを作りたい場面があれば、またお任せしてみようと思います。

関連

READYFORテックブログ

Discussion