Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 184 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
name: Build FAPI specifications

on:
push:
branches: [master]
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
build:
name: Build spec HTML
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# build-all.py runs ./pandoc-3.1.9/bin/pandoc for the FAPI 1.0 documents;
# fetch the pinned release it expects (as the old Bitbucket pipeline did).
- name: Install pandoc
run: |
curl -fsSL https://github.com/jgm/pandoc/releases/download/3.1.9/pandoc-3.1.9-linux-amd64.tar.gz \
| tar -xz pandoc-3.1.9/bin/pandoc

# Builds every spec (markdown2rfc via docker for the mmark ones, pandoc
# for FAPI 1.0) plus index.html and manifest.json, all at the repo root.
- name: Build specifications
run: ./build-all.py

- name: Assemble site
run: |
mkdir -p _site
cp *.html manifest.json _site/

- name: Upload site artifact
uses: actions/upload-artifact@v4
with:
name: site
path: _site

# The xml2rfc XML (still carrying its -NN draft-version suffix), kept as
# an artifact for draft submissions; not published to the site.
- name: Upload XML artifact
uses: actions/upload-artifact@v4
with:
name: xml
path: '*.xml'
if-no-files-found: error

# The site is served from the gh-pages branch (Pages source: "Deploy from a
# branch"): master's drafts live at the root, and per-PR previews live under
# PREVIEW-DO-NOT-USE/pr-<N>/ (removed again by preview-cleanup.yml). Same
# model as the openid/dchp repo.
publish-to-pages:
name: Publish drafts to GitHub Pages
if: github.ref == 'refs/heads/master'
needs: build
runs-on: ubuntu-latest
# Serialise gh-pages pushes so two quick merges to master can't race.
concurrency:
group: "pages"
cancel-in-progress: false
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download site artifact
uses: actions/download-artifact@v4
with:
name: site
path: ${{ runner.temp }}/site
- name: Publish to gh-pages branch
# Run a copy from outside the work tree: the script switches the
# checkout to gh-pages, which has no tools/.
run: |
cp tools/publish-gh-pages.sh "$RUNNER_TEMP/"
bash "$RUNNER_TEMP/publish-gh-pages.sh" root "$RUNNER_TEMP/site" \
"Publish FAPI drafts for ${GITHUB_SHA}"

# HTML preview of the PR's drafts, linked from a sticky PR comment. Fork PRs
# get a read-only GITHUB_TOKEN, so previews only run for branches in this
# repo.
deploy-preview:
name: Deploy PR preview to GitHub Pages
if: >
github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository
needs: build
runs-on: ubuntu-latest
concurrency:
group: preview-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Download site artifact
uses: actions/download-artifact@v4
with:
name: site
path: ${{ runner.temp }}/site
- name: Deploy preview to gh-pages branch
run: |
cp tools/publish-gh-pages.sh "$RUNNER_TEMP/"
bash "$RUNNER_TEMP/publish-gh-pages.sh" subdir \
"PREVIEW-DO-NOT-USE/pr-${{ github.event.pull_request.number }}" \
"$RUNNER_TEMP/site" \
"Preview for PR #${{ github.event.pull_request.number }}"
- name: Comment with preview links
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const prNum = context.issue.number;
const sha = context.payload.pull_request.head.sha;
// Assumes the default <owner>.github.io/<repo> Pages host (no CNAME).
const base = `https://${context.repo.owner}.github.io/${context.repo.repo}/PREVIEW-DO-NOT-USE/pr-${prNum}/`;

// Source .md -> generated .html, written by build-all.py and
// shipped inside the site artifact.
const manifest = JSON.parse(
fs.readFileSync(`${process.env.RUNNER_TEMP}/site/manifest.json`, 'utf8'));

// Link directly to the drafts whose sources this PR touches. A PR
// touching no spec sources (or only unbuilt ones) gets just the
// index link.
const changedFiles = await github.paginate(github.rest.pulls.listFiles, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNum,
per_page: 100,
});
const changed = new Set(changedFiles.map(f => f.filename));
const changedDrafts = Object.entries(manifest)
.filter(([src]) => changed.has(src))
.map(([, html]) => html)
.sort();

// Invisible marker identifying our comment, so the visible heading
// can be reworded without breaking the update-in-place matching.
const marker = '<!-- fapi-preview-comment -->';
const lines = ['📄 **HTML preview**', ''];
if (changedDrafts.length > 0) {
lines.push('Drafts changed in this PR:');
for (const html of changedDrafts) {
lines.push(`- [${html}](${base}${html})`);
}
lines.push('');
}
lines.push(`[All drafts](${base}index.html)`);
lines.push('');
lines.push(
`_Preview of ${sha}; updated on every push. For review only — ` +
'the official specifications are published at https://openid.net/specs/_');
lines.push(marker);
const body = lines.join('\n');

// Update the existing preview comment rather than adding a new one.
let existing = null;
for await (const response of github.paginate.iterator(
github.rest.issues.listComments,
{ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNum, per_page: 100 }
)) {
const found = response.data.find(c => c.body.includes(marker));
if (found) { existing = found; break; }
}

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNum,
body,
});
}
34 changes: 34 additions & 0 deletions .github/workflows/preview-cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Clean up PR preview

# Removes the PR's HTML preview (deployed to the gh-pages branch by the
# deploy-preview job in build.yml) once the PR is closed or merged.
on:
pull_request:
types: [closed]

permissions:
contents: write

jobs:
cleanup-preview:
name: Remove PR preview from GitHub Pages
# Fork PRs never get a preview (see deploy-preview in build.yml).
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
# Same group as deploy-preview, so a still-running deployment for this PR
# finishes before we delete its output.
concurrency:
group: preview-${{ github.event.pull_request.number }}
cancel-in-progress: false
steps:
# Check out the default branch for tools/: the PR's merge ref can be
# gone by the time a closed PR's workflow runs.
- uses: actions/checkout@v4
with:
ref: ${{ github.event.repository.default_branch }}
- name: Remove preview
run: |
cp tools/publish-gh-pages.sh "$RUNNER_TEMP/"
bash "$RUNNER_TEMP/publish-gh-pages.sh" delete \
"PREVIEW-DO-NOT-USE/pr-${{ github.event.pull_request.number }}" \
"Remove preview for PR #${{ github.event.pull_request.number }}"
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
.idea
.DS_Store
.DS_Store
*~

# build outputs (root-anchored: FAPI_1.0/ has tracked .html/.xml artifacts)
/*.html
/*.xml
/manifest.json
/_site/
/pandoc-3.1.9/
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This is the official repository for OpenID Foundation Financial-grade API (FAPI) Working Group.

The latest drafts are built automatically from this repository and published at <https://openid.github.io/fapi/>. These reflect in-progress edits; the official specifications are published at <https://openid.net/specs/>.

### What is this repository for? ###

* FAPI 1.0 - This is a profile of OpenID Connect.
Expand All @@ -26,7 +28,7 @@ You can find the overview and rationale of the working group at [the WG page](ht
* You MUST execute the Contributor Agreement either by
* [Electronic Signature](http://openid.net/intellectual-property/) and notify openid-specs-fapi-owner@lists.openid.net; OR
* print this [PDF](http://openid.net/wordpress-content/uploads/2010/01/paper-contribution-agreement-20100122.pdf) and fill, sign, scan, and send it to openid-specs-fapi-owner@lists.openid.net.
* You MUST file an issue to [the issue tracker](https://bitbucket.org/openid/fapi/issues?status=new&status=open) before contributing a code.
* You MUST file an issue to [the issue tracker](https://github.com/openid/fapi/issues) before contributing a code.
* You MUST test that the contributed code compiles without error.

### Who do I talk to? ###
Expand Down
43 changes: 0 additions & 43 deletions bitbucket-pipelines.yml

This file was deleted.

30 changes: 25 additions & 5 deletions build-all.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# exits with appropriate success / failure return code

import glob
import json
import os
import re
import sys
Expand Down Expand Up @@ -47,10 +48,19 @@
'./FAPI_1.0/openid-financial-api-part-2-1_0.md'
]

# Pinned by digest so the rendering is reproducible: an untagged/:latest image
# could silently change the output between identical commits. Regenerate the
# digest with `docker buildx imagetools inspect danielfett/markdown2rfc:latest`.
MD2RFC_IMAGE = 'danielfett/markdown2rfc@sha256:7b4412559d6ba5db45a14174a28da5b240512e7c2a886a5e4adb44e5e67f34ca'

failed = []

files_generated = []

# source .md -> generated .html, written to manifest.json for CI to link the
# drafts changed in a pull request from the preview comment
manifest = {}

def get_output_filename(fname):
# get the output filename, i.e. do what https://github.com/oauthstuff/markdown2rfc/blob/master/make.sh#L18 does
# and find the line like: value = "fapi-2_0-baseline-01"
Expand Down Expand Up @@ -88,12 +98,13 @@ def execute_command(cmd, fname, outputfname):
os.rename(outputfname, newoutputfname)
outputfname = newoutputfname
print("Renamed output to "+outputfname)
files_generated.append(newoutputfname)
files_generated.append(outputfname)
manifest[fname[2:] if fname.startswith('./') else fname] = outputfname
print()

def process_spec(fname):
currentdir = os.getcwd()
cmd = [ 'docker', 'run', '-v', currentdir+':/data', 'danielfett/markdown2rfc', fname ]
cmd = [ 'docker', 'run', '-v', currentdir+':/data', MD2RFC_IMAGE, fname ]
print("Running: " + ' '.join(cmd))
outputfname = get_output_filename(fname)
outputfname += ".html"
Expand Down Expand Up @@ -133,9 +144,16 @@ def generate_index():
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>OpenID Foundation FAPI Working Group Drafts</title>
<link rel="stylesheet" href="../base.css" type="text/css"/>
<style type="text/css">
<!--
body {
font-family: sans-serif;
margin: 2em;
}
.navigation li {
display: inline;
margin-right: 1.5em;
}
.style1 {
color: #FF0000;
font-weight: bold;
Expand All @@ -158,8 +176,8 @@ def generate_index():
<div id="nav" class="column span-18 append-1 prepend-1">
<ul class="navigation">
<li><a href='https://openid.net/wg/fapi/'>About</a></li>
<li><a href='https://bitbucket.org/openid/fapi/'>Repository</a></li>
<li><a href="https://bitbucket.org/openid/fapi/issues?status=new&status=open">Issues</a></li>
<li><a href='https://github.com/openid/fapi'>Repository</a></li>
<li><a href='https://github.com/openid/fapi/issues'>Issues</a></li>
</ul>
</div>
<div id="content">
Expand All @@ -183,6 +201,8 @@ def generate_index():

walk_tree()
generate_index()
with open('manifest.json', 'w') as f:
json.dump(manifest, f, indent=2, sort_keys=True)
if failed:
print("The processing of some specifications failed:")
for f in failed:
Expand Down
Loading
Loading