Skip to content

Commit b2090e8

Browse files
committed
Add action to dynamically build README
1 parent fbb2931 commit b2090e8

File tree

8 files changed

+733
-0
lines changed

8 files changed

+733
-0
lines changed

.github/workflows/build.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: README builder
2+
on:
3+
workflow_dispatch:
4+
schedule:
5+
- cron: '0 */6 * * *'
6+
7+
jobs:
8+
9+
build:
10+
runs-on: ubuntu-latest
11+
continue-on-error: true
12+
steps:
13+
- name: Check out repository
14+
uses: actions/checkout@v2
15+
16+
- name: Set up Node.js
17+
uses: actions/setup-node@v1
18+
19+
- name: Install packages
20+
run: npm install
21+
22+
- name: (Re)build README
23+
run: npm --silent run build > README.md
24+
env:
25+
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
26+
27+
- name: Check for changes (fail if none)
28+
run: |
29+
! git diff --quiet
30+
31+
- name: Commit changes if required
32+
if: ${{ success() }}
33+
run: |
34+
git config --global user.email "[email protected]"
35+
git config --global user.name "jung-thomas"
36+
git add README.md
37+
git commit -m 'update README' || exit 0
38+
git push
39+
env:
40+
GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}

.gitignore

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
8+
# Runtime data
9+
pids
10+
*.pid
11+
*.seed
12+
*.pid.lock
13+
14+
# Directory for instrumented libs generated by jscoverage/JSCover
15+
lib-cov
16+
17+
# Coverage directory used by tools like istanbul
18+
coverage
19+
20+
# nyc test coverage
21+
.nyc_output
22+
23+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24+
.grunt
25+
26+
# Bower dependency directory (https://bower.io/)
27+
bower_components
28+
29+
# node-waf configuration
30+
.lock-wscript
31+
32+
# Compiled binary addons (https://nodejs.org/api/addons.html)
33+
build/Release
34+
35+
# Dependency directories
36+
node_modules/
37+
jspm_packages/
38+
39+
# TypeScript v1 declaration files
40+
typings/
41+
42+
# Optional npm cache directory
43+
.npm
44+
45+
# Optional eslint cache
46+
.eslintcache
47+
48+
# Optional REPL history
49+
.node_repl_history
50+
51+
# Output of 'npm pack'
52+
*.tgz
53+
54+
# Yarn Integrity file
55+
.yarn-integrity
56+
57+
# dotenv environment variables file
58+
.env
59+
60+
# next.js build output
61+
.next
62+
63+
mta_archives/
64+
default-*.json
65+
66+
# dotenv environment variables file
67+
.env
68+
69+
# Visual Studio Code
70+
.vscode

README1.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
![SAP Tech Bytes header image](header-image.png)
2+
3+
[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/sap-tech-bytes)](https://api.reuse.software/info/github.com/SAP-samples/sap-tech-bytes)
4+
5+
This repository provides small sets of configuration & code relating to video episodes, blog posts and other content in the SAP Tech Bytes initiative, which it accompanies.
6+
7+
## Description
8+
9+
Where there's sample code or configuration to share, specifically relating to an SAP Tech Bytes episode or post, you'll most likely find it here. The structure of this repository is simple - there are individual **branches**, each one relating to a specific SAP Tech Bytes episode or blog post.
10+
11+
Perhaps most of the time you'll be arriving at this repository, coming from such an episode or blog post, so you'll be sent to the appropriate branch like that. But if you're starting here and want to find out to which SAP Tech Bytes episode or blog post a given branch-based sample relates, you'll find the back link in the README in that branch.

README2.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## Requirements
2+
3+
Requirements may differ from sample to sample, so please see the individual README files as appropriate.
4+
5+
## Download and installation
6+
7+
To enjoy this content, you don't have to download or install anything. But you can of course clone this repository to have the content available to you locally.
8+
9+
From there, in order to try out a sample, simply check out the desired branch, and follow the instructions in the README there.
10+
11+
## Support
12+
13+
For the most part, this content is provided "as-is" with no other support. But we will certainly also respond to well-formed and detailed issues raised against this repository.
14+
15+
## Contributing
16+
17+
The general context of this repository is as a consumable store of sample configuration & code for SAP Tech Bytes episodes and blog posts. If you find you do have something to contribute, for example to offer fixes or improvements, please send an appropriate pull request (PR). Due to legal reasons, contributors will be asked to accept a [Developer Certificate of Origin (DCO)](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin) on submitting their first PR to this project. This DCO acceptance can be done in the PR itself - look out for the CLA assistant that will guide you through the simple process. SAP uses [the standard DCO text of the Linux Foundation](https://developercertificate.org/). Thank you!
18+
19+
## License
20+
21+
Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSE) file.

build.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
const Parser = require('rss-parser')
2+
const request = require('then-request');
3+
const parser = new Parser({
4+
headers: {
5+
'Accept': 'application/atom+xml'
6+
}
7+
})
8+
9+
const Handlebars = require('handlebars')
10+
const source = require('./templateREADME')
11+
const template = Handlebars.compile(source)
12+
const { Octokit } = require("@octokit/core")
13+
const { createActionAuth } = require("@octokit/auth-action")
14+
const auth = createActionAuth()
15+
16+
17+
const URLYouTube = 'https://www.youtube.com/feeds/videos.xml?playlist_id=PL6RpkC85SLQC3HBShmlMaPu_nL--4f20z'
18+
const URLSCN = 'https://content.services.sap.com/feed?type=blogpost&tags=sap-tech-bytes'
19+
20+
const sort_by = (field, reverse, primer) => {
21+
const key = primer ?
22+
(x) => {
23+
return primer(x[field])
24+
} :
25+
(x) => {
26+
return x[field]
27+
}
28+
reverse = !reverse ? 1 : -1
29+
return (a, b) => {
30+
return a = key(a), b = key(b), reverse * ((a > b) - (b > a))
31+
}
32+
}
33+
34+
const branchProcessing = async (item, octokit) => {
35+
let branchDetails = await octokit.request('GET /repos/{owner}/{repo}/branches/{branch}', {
36+
owner: 'SAP-samples',
37+
repo: 'sap-tech-bytes',
38+
branch: item.name
39+
})
40+
item.url = branchDetails.data._links.html
41+
console.log(branchDetails.data)
42+
item.authorName = branchDetails.data.commit.commit.author.name
43+
return Promise.resolve(item)
44+
}
45+
46+
const getBranches = async octokit => {
47+
//Read List of Branches in the SAP Tech Bytes Repo
48+
let branches = await octokit.request('GET /repos/{owner}/{repo}/branches', {
49+
owner: 'SAP-samples',
50+
repo: 'sap-tech-bytes'
51+
})
52+
53+
//Delete the main branch from the list
54+
let indexOfMain = branches.data.indexOf(branches.data.find(obj => {
55+
return obj.name === 'main'
56+
}))
57+
if (indexOfMain !== -1) { branches.data.splice(indexOfMain, 1) }
58+
59+
//Sort by branch name
60+
branches.data.sort(sort_by('name', true, (a) => a.toUpperCase()))
61+
62+
//Return the most recent 6 branches and lookup the details for each branch
63+
branchesNew = await Promise.all(branches.data.slice(0, 6).map(item => branchProcessing(item, octokit)))
64+
65+
return branchesNew
66+
}
67+
68+
const getBlogPosts = async _ => {
69+
//Read List of Blog Posts in the SAP Community Netwwork with tag sap-tech-bytes
70+
const feed = await parser.parseURL(URLSCN)
71+
72+
//Sort by date
73+
feed.items.sort(sort_by('pubDate', true))
74+
75+
//Return the most recent 6 Blog Posts
76+
const items = feed.items.slice(0, 6).map(item => {
77+
item.date = new Date(item.pubDate).toDateString()
78+
return item
79+
})
80+
return items
81+
}
82+
83+
const getYoutubeVideos = async _ => {
84+
//Read List of Videos in the SAP Tech Bytes Playlist on YouTube
85+
const feedNew = await parser.parseURL(URLYouTube)
86+
87+
//Sort by date
88+
feedNew.items.sort(sort_by('pubDate', true))
89+
90+
//Return the most recent 6 Videos
91+
const itemsNew = feedNew.items.slice(0, 6).map(item => {
92+
item.date = new Date(item.pubDate).toDateString()
93+
return item
94+
})
95+
return itemsNew
96+
}
97+
98+
const getStaticREADME = async _ => {
99+
const fs = require('fs')
100+
return [readme1, readme2] = await Promise.all([
101+
fs.readFileSync('./README1.md', 'utf8'),
102+
fs.readFileSync('./README2.md', 'utf8')
103+
])
104+
}
105+
106+
const main = async _ => {
107+
try {
108+
const authentication = await auth()
109+
const octokit = new Octokit({ auth: authentication.token })
110+
let [branches, blogPosts, videos, [readme1, readme2]] = await Promise.all([
111+
getBranches(octokit),
112+
getBlogPosts(),
113+
getYoutubeVideos(),
114+
getStaticREADME()
115+
])
116+
console.log(template({ readme1, readme2, blogPosts, videos, branches }))
117+
} catch (error) {
118+
console.log(`${error}`)
119+
process.exit(1)
120+
}
121+
}
122+
123+
main()

0 commit comments

Comments
 (0)