こちらは、GitHub Actions Advent Calendar 2020 18日目の記事になります。
はじめに
GitHub Actions を使っていて、アーティファクト(成果物)をリポジトリのタブから
パイプラインを選択して探すの面倒だと思ったことはないでしょうか?
自分もAndroidの開発でアーティファクトにアップロードしたアプリを
インストールするのが大変だと感じていました。
なので今回は、Github Actions でアップロードしたアーティファクトを
簡単にダウンロードできる Webアプリ を作ってみました。
(といっても、1ページの簡単なものですが)
作成したもの
[![TakenokoTech/Unitool - GitHub](https://gh-card.dev/repos/TakenokoTech/apricot.svg)](https://github.com/TakenokoTech/apricot) Webページ:https://takenokotech.github.io/apricotシステム構成図
シーケンス
認可〜トークン取得
https://docs.github.com/ja/free-pro-team@latest/developers/apps/authorizing-oauth-apps
トークン取得のPOSTは、CORSを回避するために CORS Anywhere を用いてプロキシしました。
export async function getToken(clientId: string, clientSecret: string, redirectUri: string, oauthScope: string, code: string = null): Promise<string> {
if (!code) {
window.location.href = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${oauthScope}`;
return null;
}
const accessTokenUrl = "https://cors-anywhere.herokuapp.com/https://github.com/login/oauth/access_token";
const response = await fetch(`${accessTokenUrl}?client_id=${clientId}&client_secret=${clientSecret}&code=${code}&redirect_uri=${redirectUri}`, {
method: "POST",
headers: {
Accept: "application/json",
},
});
const { access_token, scope, token_type } = await response.json();
return access_token
}
ユーザー情報取得
https://docs.github.com/en/free-pro-team@latest/rest/reference/users#get-the-authenticated-user
ユーザー情報に紐づく様々な公開データが取れます。
export async function getUser(accesstoken: string): Promise<User> {
const apiUrl = "https://api.github.com/user";
const resp = await fetch(apiUrl, {
headers: {
Authorization: `token ${accesstoken}`,
Accept: "application/vnd.github.v3+json",
},
});
// repos_urlは、下のリポジトリ取得で使われるURLと同じ
const { login, repos_url } = await resp.json();
return login
リポジトリ取得
https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#list-organization-repositories
ユーザーが公開しているリポジトリが見えます。
export async function getRepos(userName: string): Promise<RepoItem[]> {
const url = `https://api.github.com/users/${userName}/repos?per_page=100`;
const resp = await fetch(url);
const json = await resp.json();
const repos =
json.map((repo) => ({
name: repo.name,
full_name: repo.full_name,
html_url: repo.html_url,
})) || [];
return repos;
}
ワークフロー取得
https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#list-workflow-runs-for-a-repository
コミットログなどが取れます。
export async function getWorkflow(userName: string, repoName: string): Promise<WorkflowItem[]> {
const url = `https://api.github.com/repos/${userName}/${repoName}/actions/runs`;
const resp = await fetch(url);
const json = await resp.json();
const workflows = json.workflow_runs?.map((workflow) => workflow) || [];
return workflows;
}
アーティファクト取得
https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#list-artifacts-for-a-repository
アーティファクトURLはワークフローから取得できます。
このgetArtifactUrl
ではファイルを取得するための期限つきURLが発行されるので、そちらを使ってファイルを取得します。
export async function getArtifactUrl(user: string, accesstoken: string, artifactUrl: string): Promise<string> {
const response = await fetch(artifactUrl, {
headers: {
Authorization: `token $accesstoken`,
Accept: "application/vnd.github.v3+json",
"Content-Type": "application/zip",
"User-Agent": user,
},
});
return response.url;
}
// getArtifactUrlで取得したURLを使ってファイルをダウンロードする。
const url = await getArtifactUrl(this.state.artifactUrl);
const link = document.createElement("a");
link.download = this.state.name;
link.href = url;
link.click();
まとめ
以上、今回作った Apricot の技術解説でした。
ご覧いただきありがとうございました。