概要
前回はホットスポットプロファイルの可視化を行った。
既にGitHubPagesがあるので、GitHubActionsを使ってデプロイする。
ディレクトリ構造
GitHub Pagesの作成にはastroを使っている。
今回は、astroをビルドしたフォルダにGitHub Actionsを使ってhotspot.jsonを追加する仕組みとする。
- docs
- astro
- dist ← astroをビルドして生成されるフォルダ。このフォルダをGitHub Pagesとしてデプロイする
- crimes-scene-hotspots ← publicからコピーされたディレクトリ
- index.html
+ - hotspots.json ← github actionsで生成するJSONファイル
- public
- crimes-scene-hotspots
- index.html
ソースコード
GitHub Actions
hotspotプロファイルの作成を除いた部分は割愛している。
.github/workflows/github-pages.yml
# 省略
env:
BUILD_PATH: './docs/astro'
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# デフォルトでは 1 に設定されており、最新のコミット履歴しか参照できない
# 0 に変更することで、リポジトリの完全なコミット履歴を参照できるようになる
fetch-depth: 0
# 省略
- name: Build with Astro
run: |
npm run astro build \
--site "${{ steps.pages.outputs.origin }}" \
--base "${{ steps.pages.outputs.base_path }}"
working-directory: ${{ env.BUILD_PATH }}
- name: Set up JDK 21
uses: actions/setup-java@v4.5.0
with:
distribution: 'temurin'
java-version: '21'
- name: Download Code Maat
run: wget https://github.com/adamtornhill/code-maat/releases/download/v1.0.4/code-maat-1.0.4-standalone.jar
working-directory: ./docs/code-maat
- name: create git log
run: git log --all --numstat --date=short --pretty=format:'--%h--%ad--%aN' --no-renames --after=2023-01-01 > ./logfile.log
working-directory: ./docs/code-maat
- name: Run Code Maat
run: java -jar code-maat-1.0.4-standalone.jar -l logfile.log -c git2 -c git2 -a revisions > ./revisions.csv
working-directory: ./docs/code-maat
- name: Run Cloc
run: docker run --rm -v .:/tmp aldanial/cloc --unix --by-file --csv --quiet --timeout 10 --vcs=git --exclude-dir=docs,.vscode,.github --not-match-f=\.json --report-file=./docs/code-maat/complexity.csv
- uses: actions/setup-python@v5
with:
python-version: '3.13'
- run: python csv_as_enclosure_json.py --structure complexity.csv --weights revisions.csv > ../astro/dist/crime-scene-hotspots/hotspots.json
working-directory: ./docs/code-maat
# 省略
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ${{ env.BUILD_PATH }}/dist
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
name: Deploy
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
ホットスポットの可視化
crime-scene-hotspots.html を参考に、 d3をv3からv7にマイグレーションしたものを使用する。
docs/astro/crime-scene-hotspots/index.html
<!DOCTYPE html>
<meta charset="utf-8" />
<style>
.node {
cursor: pointer;
}
.node:hover {
stroke: #000;
stroke-width: 1.5px;
}
.node--root {
stroke: #777;
stroke-width: 2px;
}
.node--leaf {
fill: white;
stroke: #777;
stroke-width: 1px;
}
.label {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
text-anchor: middle;
fill: white;
text-shadow: 0 1px 0 #000, 1px 0 0 #000, -1px 0 0 #000, 0 -1px 0 #000;
}
.label,
.node--root,
.node--leaf {
pointer-events: none;
}
</style>
<body>
<script type="module">
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
const margin = 10,
outerDiameter = 960,
innerDiameter = outerDiameter - margin - margin;
const x = d3.scaleLinear().range([0, innerDiameter]);
const y = d3.scaleLinear().range([0, innerDiameter]);
const color = d3.scaleLinear()
.domain([-1, 5])
.range(['hsl(185,60%,99%)', 'hsl(187,40%,70%)'])
.interpolate(d3.interpolateHcl);
const pack = d3.pack()
.padding(2)
.size([innerDiameter, innerDiameter]);
const svg = d3
.select('body')
.append('svg')
.attr('width', outerDiameter)
.attr('height', outerDiameter)
.append('g')
.attr('transform', 'translate(' + margin + ',' + margin + ')');
const d3Json = await d3.json('hotspots.json');
const root = d3.hierarchy(d3Json).sum(d => d.size);
const nodes = pack(root).descendants();
let focus = root;
svg
.append('g')
.selectAll('circle')
.data(nodes)
.enter()
.append('circle')
.attr('class', function (d) {
return d.parent
? d.children
? 'node'
: 'node node--leaf'
: 'node node--root';
})
.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')';
})
.attr('r', function (d) {
return d.r;
})
.style('fill', function (d) {
return d.weight > 0.0
? 'darkred'
: d.children
? color(d.depth)
: 'WhiteSmoke';
})
.style('fill-opacity', function (d) {
return d.weight;
})
.on('click', function (event, d) {
return zoom(event, focus === d ? root : d);
});
svg
.append('g')
.selectAll('text')
.data(nodes)
.enter()
.append('text')
.attr('class', 'label')
.attr('transform', function (d) {
return `translate(${d.x}, ${d.y})`;
})
.style('fill-opacity', function (d) {
return d.parent === root ? 1 : 0;
})
.style('display', function (d) {
return d.parent === root ? null : 'none';
})
.text(function (d) {
return d.data.name;
});
d3.select(window).on('click', function (event) {
zoom(event, root);
});
function zoom(event, d) {
const focus0 = focus;
focus = d;
const k = innerDiameter / d.r / 2;
x.domain([d.x - d.r, d.x + d.r]);
y.domain([d.y - d.r, d.y + d.r]);
event.stopPropagation();
const transition = svg
.selectAll("text,circle")
.transition()
.duration(event.altKey ? 7500 : 750)
.attr("transform", function (d) {
return `translate(${x(d.x)}, ${y(d.y)})`;
});
transition.filter("circle").attr("r", function (d) {
return k * d.r;
});
transition
.filter("text")
.filter(function (d) {
return d.parent === focus || d.parent === focus0;
})
.style("fill-opacity", function (d) {
return d.parent === focus ? 1 : 0;
})
.on("start", function (d) {
if (d.parent === focus) this.style.display = "inline";
})
.on("end", function (d) {
if (d.parent !== focus) this.style.display = "none";
});
}
d3.select(self.frameElement).style("height", outerDiameter + "px");
</script>
</body>
参考
GitHubPagesに開発ドキュメントをデプロイする総集編
ホットスポットプロファイルの可視化を試してみたメモ
GitHub Actionsでコミット履歴を参照する