Skip to content

Commit d01c36d

Browse files
committedDec 6, 2021
feat: initial commit with github action to update notion tasks
1 parent 0a4f9d8 commit d01c36d

File tree

8 files changed

+2041
-0
lines changed

8 files changed

+2041
-0
lines changed
 

Diff for: ‎.editorconfig

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true

Diff for: ‎.eslintrc.js

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
commonjs: true,
5+
es2021: true,
6+
},
7+
extends: 'eslint:recommended',
8+
parserOptions: {
9+
ecmaVersion: 13,
10+
},
11+
globals: {
12+
process: 'readonly',
13+
},
14+
rules: {
15+
'no-extend-native': [ 'error', { exceptions: [ 'Array' ] } ],
16+
'no-global-assign': [ 'error', { exceptions: [ 'self' ] } ],
17+
'generator-star-spacing': 'off',
18+
// eslint-disable-next-line no-undef
19+
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
20+
'no-trailing-spaces': [ 'error', { skipBlankLines: true } ],
21+
'array-bracket-spacing': [ 'error', 'always' ],
22+
'arrow-body-style': [ 'warn', 'as-needed' ],
23+
'standard/no-callback-literal': 0,
24+
'comma-dangle': [
25+
'warn',
26+
{
27+
arrays: 'always-multiline',
28+
objects: 'always-multiline',
29+
imports: 'never',
30+
exports: 'never',
31+
functions: 'ignore',
32+
},
33+
],
34+
'curly': [ 'warn', 'multi-line' ],
35+
'eol-last': [ 'error', 'always' ],
36+
'indent': [ 'error', 2, { SwitchCase: 1, VariableDeclarator: 1 } ],
37+
'max-len': [
38+
'warn',
39+
{
40+
code: 140,
41+
ignoreComments: true,
42+
ignoreTrailingComments: true,
43+
ignoreStrings: true,
44+
ignorePattern: '.+=".+"',
45+
},
46+
],
47+
'no-multiple-empty-lines': [ 'error', { max: 1, maxEOF: 1 } ],
48+
'no-prototype-builtins': 0,
49+
'object-curly-spacing': [ 'error', 'always' ],
50+
'object-property-newline': [ 'error', { allowAllPropertiesOnSameLine: true } ],
51+
'padded-blocks': 'off',
52+
'prefer-const': [ 'error', { destructuring : 'all' } ],
53+
'prefer-template': 'error',
54+
'quote-props': [ 'error', 'consistent-as-needed' ],
55+
'quotes': [
56+
'error',
57+
'single',
58+
{
59+
avoidEscape: true,
60+
// TODO: Remove this rule and autofix,
61+
// as we don't need useless template literals
62+
allowTemplateLiterals: true,
63+
},
64+
],
65+
'semi': [ 'error', 'never', { beforeStatementContinuationChars: 'never' } ],
66+
'space-before-function-paren': [ 'warn', 'always' ],
67+
'spaced-comment': [
68+
'error',
69+
'always',
70+
{
71+
block: {
72+
markers: [ '!' ],
73+
},
74+
},
75+
],
76+
},
77+
}

Diff for: ‎.github/workflows/eslint.yml

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# This is a basic workflow to help you get started with Actions
2+
name: Lint
3+
4+
# Controls when the action will run. Triggers the workflow on push or pull request
5+
# events but on dev and staging branches
6+
on:
7+
pull_request:
8+
branches:
9+
- main
10+
- 'feature/**'
11+
- 'features/**'
12+
push:
13+
branches:
14+
- main
15+
16+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
17+
jobs:
18+
prepare:
19+
name: Prepare & Cleanup Previous Runs
20+
if: always()
21+
runs-on: ubuntu-latest
22+
outputs:
23+
commit_message: ${{ steps.get_message.outputs.commit_message }}
24+
25+
steps:
26+
- uses: actions/checkout@v1
27+
- uses: rokroskar/workflow-run-cleanup-action@v0.2.2
28+
env:
29+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
30+
- id: get_message
31+
name: Set Commit Message
32+
run: echo ::set-output name=commit_message::$(git log --format=%B -n 1 ${{ github.event.after }})
33+
- name: Show Commit Message
34+
run: echo "${{ steps.get_message.outputs.commit_message }}"
35+
36+
lint-and-units:
37+
name: ESLint
38+
needs: prepare
39+
timeout-minutes: 45
40+
if: (github.event.pull_request.draft == false) && !startsWith(github.head_ref, 'tech') && !startsWith(github.head_ref, 'doc') && !contains(needs.prepare.outputs.commit_message, '[skip ci]')
41+
# The type of runner that the job will run on
42+
runs-on: ubuntu-18.04
43+
steps:
44+
- name: Show Commit Message
45+
run: echo "${{ needs.prepare.outputs.commit_message }}"
46+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
47+
- uses: actions/checkout@v2
48+
- name: Use Node.js
49+
uses: actions/setup-node@v1
50+
with:
51+
node-version: '16.x'
52+
- name: Run ESLint
53+
if: always()
54+
run: npm run lint

Diff for: ‎package-lock.json

+1,611
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: ‎package.json

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"name": "notion-scripts",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"lint": "npx eslint --ext .js ."
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/coursedog/notion-scripts.git"
13+
},
14+
"keywords": [],
15+
"author": "",
16+
"license": "ISC",
17+
"bugs": {
18+
"url": "https://github.com/coursedog/notion-scripts/issues"
19+
},
20+
"homepage": "https://github.com/coursedog/notion-scripts#readme",
21+
"dependencies": {
22+
"@actions/core": "^1.6.0",
23+
"@actions/github": "^5.0.0",
24+
"@notionhq/client": "^0.4.9"
25+
},
26+
"devDependencies": {
27+
"eslint": "^8.3.0",
28+
"husky": "^7.0.4",
29+
"lint-staged": "^12.1.2"
30+
},
31+
"husky": {
32+
"hooks": {
33+
"pre-commit": "lint-staged"
34+
}
35+
},
36+
"lint-staged": {
37+
"src/**/*.{js,vue}": [
38+
"eslint --fix",
39+
"git add"
40+
],
41+
"server/**/*.js": [
42+
"eslint --fix",
43+
"git add"
44+
],
45+
"shared/**/*.js": [
46+
"eslint --fix",
47+
"git add"
48+
],
49+
"scripts/**/*.js": [
50+
"eslint --fix",
51+
"git add"
52+
],
53+
"packages/**/*.ts": [
54+
"eslint --fix",
55+
"git add"
56+
],
57+
"tests/e2e/specs/**/*.js": [
58+
"eslint --fix",
59+
"git add"
60+
]
61+
}
62+
}

Diff for: ‎update_notion/action.yml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: 'Update Notion Task Status'
2+
description: 'Github Action to Update Notion Task when a PR has been merged to a particular stage'
3+
inputs:
4+
NOTION_API_KEY: # id of input
5+
description: 'API Key to get access to the notion board'
6+
required: true
7+
default: ''
8+
NOTION_DATABASE_TOKEN: # id of input
9+
description: 'Token to identify the task board in which the change is going to happen'
10+
required: true
11+
default: ''
12+
runs:
13+
using: 'node16'
14+
main: 'index.js'

Diff for: ‎update_notion/index.js

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const core = require('@actions/core')
2+
const { Octokit } = require('@octokit/rest')
3+
4+
const Notion = require('./../utils/notion')
5+
6+
try {
7+
const {
8+
GITHUB_REF,
9+
} = process.env
10+
11+
if (GITHUB_REF === 'refs/heads/master') {
12+
_updateNotionStatuses('master')
13+
} else if (GITHUB_REF === 'refs/heads/staging') {
14+
_updateNotionStatuses('staging')
15+
} else if (GITHUB_REF === 'refs/heads/dev') {
16+
_updateNotionStatuses('dev')
17+
}
18+
} catch (error) {
19+
core.setFailed(error.message)
20+
}
21+
22+
/**
23+
* Function to update the status of the tasks based on
24+
* the recent commit is getting merged to which branch
25+
*
26+
* @param {'dev' | 'staging' | 'master' } branch Name of the branch to which the commit is getting merged to
27+
*/
28+
async function _updateNotionStatuses (branch) {
29+
30+
const {
31+
GITHUB_REPOSITORY,
32+
GITHUB_TOKEN,
33+
GITHUB_OWNER,
34+
} = process.env
35+
36+
const octokit = new Octokit({
37+
auth: GITHUB_TOKEN,
38+
})
39+
40+
const NOTION_DATABASE_TOKEN = core.getInput('NOTION_DATABASE_TOKEN')
41+
const NOTION_API_KEY = core.getInput('NOTION_API_KEY')
42+
43+
const notionUtil = new Notion({
44+
apiKey: NOTION_API_KEY,
45+
databaseToken: NOTION_DATABASE_TOKEN,
46+
})
47+
48+
const repositoryName = GITHUB_REPOSITORY.split('/').pop()
49+
50+
// Get most recent commit to branch
51+
const { data } = await octokit.rest.repos.getCommit({
52+
owner: GITHUB_OWNER,
53+
repo: GITHUB_REPOSITORY,
54+
ref: branch,
55+
perPage: 1,
56+
page: 1,
57+
})
58+
59+
const {
60+
commit: {
61+
message: commitMessage,
62+
},
63+
} = data
64+
65+
switch (branch) {
66+
case 'master':
67+
if (commitMessage.includes('from coursedog/staging')) {
68+
// Update all tasks that are in Completed Staging to Completed Prod
69+
notionUtil.updateByStatus('Completed (Staging)', 'Completed (Production)')
70+
}
71+
break
72+
case 'staging':
73+
if (commitMessage.includes('from coursedog/dev')) {
74+
// Update all tasks that are in Completed Dev to Completed Staging
75+
notionUtil.updateByStatus('Completed (Dev)', 'Completed (Staging)')
76+
} else if (commitMessage.match(/#+[0-9]/)) {
77+
// direct from open PR to staging
78+
const prNumber = commitMessage.split('#')[1].replace(/\D/g, '')
79+
notionUtil.updateByPR(`${repositoryName}/pull/${prNumber}`, 'Completed (Staging)')
80+
}
81+
break
82+
case 'dev':
83+
if (commitMessage.match(/#+[0-9]/)) {
84+
// direct from open PR to dev
85+
const prNumber = commitMessage.split('#')[1].replace(/\D/g, '')
86+
notionUtil.updateByPR(`${repositoryName}/pull/${prNumber}`, 'Completed (Dev)')
87+
}
88+
break
89+
90+
default:
91+
break
92+
}
93+
}

Diff for: ‎utils/notion.js

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
const { Client }= require('@notionhq/client')
2+
3+
class Notion {
4+
constructor ({ apiKey, databaseToken }) {
5+
// Retrieving all the input parameters relevant to notion
6+
this.notionDatabaseToken = databaseToken
7+
8+
// Initializing the notion client
9+
this.client = new Client({ auth: apiKey })
10+
this.labels = {
11+
GITHUB_PR: 'GitHub PR',
12+
STATUS: 'Status',
13+
DATE_COMPLETED: 'Date Completed',
14+
}
15+
}
16+
17+
/**
18+
* Function to update the status of a particular task from one to the other one
19+
*
20+
* @param {String} originalStatus Status from which the task is to be moved
21+
* @param {String} newStatus Status to which the status is to be moved
22+
*/
23+
async updateByStatus (originalStatus, newStatus) {
24+
console.log('Updating all Notion tasks from', originalStatus, 'to', newStatus)
25+
const databaseId = this.notionDatabaseToken
26+
const {
27+
GITHUB_REPOSITORY,
28+
} = process.env
29+
const repositoryName = GITHUB_REPOSITORY.split('/').pop()
30+
31+
const listOfTasks = await this.client.databases.query({
32+
database_id: databaseId,
33+
filter: {
34+
and: [
35+
{
36+
property: this.labels.STATUS,
37+
select: {
38+
equals: originalStatus,
39+
},
40+
},
41+
{
42+
property: this.labels.GITHUB_PR,
43+
text: {
44+
contains: repositoryName,
45+
},
46+
},
47+
],
48+
},
49+
})
50+
for (let i = 0; i < listOfTasks.results.length; i++) {
51+
const updatedTasks = await this.client.pages.update({
52+
page_id: listOfTasks.results[i].id,
53+
properties: {
54+
Status: {
55+
select: {
56+
name: newStatus,
57+
},
58+
},
59+
},
60+
})
61+
console.log('Updated', updatedTasks)
62+
}
63+
}
64+
65+
/**
66+
* Function to promote the task by the Github PR field
67+
*
68+
* @param {String} pr PR URL for which the status is to be updated
69+
* @param {String} newStatus New status to which the task is to be promoted
70+
*/
71+
async updateByPR (pr, newStatus) {
72+
console.log('Updating one Notion task with PR', pr, 'to', newStatus)
73+
const databaseId = this.notionDatabaseToken
74+
const listOfTasks = await this.client.databases.query({
75+
database_id: databaseId,
76+
filter: {
77+
and: [
78+
{
79+
property: this.labels.GITHUB_PR,
80+
text: {
81+
ends_with: pr,
82+
},
83+
},
84+
{
85+
property: this.labels.STATUS,
86+
select: {
87+
does_not_equal: 'Completed (old)',
88+
},
89+
},
90+
{
91+
property: this.labels.STATUS,
92+
select: {
93+
does_not_equal: 'Completed (Production)',
94+
},
95+
},
96+
],
97+
},
98+
})
99+
for (let i = 0; i < listOfTasks.results.length; i++) {
100+
const updatedTasks = await this.client.pages.update({
101+
page_id: listOfTasks.results[i].id,
102+
properties: {
103+
[this.labels.STATUS]: {
104+
select: {
105+
name: newStatus,
106+
},
107+
},
108+
[this.labels.DATE_COMPLETED]: {
109+
date: {
110+
start: new Date().toISOString(),
111+
},
112+
},
113+
},
114+
})
115+
console.log('Updated', updatedTasks)
116+
}
117+
}
118+
119+
}
120+
121+
module.exports = Notion

0 commit comments

Comments
 (0)
Please sign in to comment.