Merge branch 'develop'

This commit is contained in:
antelle 2020-04-09 07:18:27 +02:00
commit 614f61ce29
No known key found for this signature in database
GPG Key ID: 094A2F2D6136A4EE
18 changed files with 26850 additions and 76 deletions

View File

@ -0,0 +1,12 @@
name: 'Publish release'
description: 'Publish a release and update the release notes'
inputs:
version:
description: 'Release version'
required: true
id:
description: 'Release ID'
required: true
runs:
using: 'node12'
main: 'dist/index.js'

File diff suppressed because it is too large Load Diff

419
.github/actions/publish-release/package-lock.json generated vendored Normal file
View File

@ -0,0 +1,419 @@
{
"name": "publish-release",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@actions/core": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.3.tgz",
"integrity": "sha512-Wp4xnyokakM45Uuj4WLUxdsa8fJjKVl1fDTsPbTEcTcuu0Nb26IPQbOtjmnfaCPGcaoPOOqId8H9NapZ8gii4w=="
},
"@actions/exec": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.3.tgz",
"integrity": "sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA==",
"requires": {
"@actions/io": "^1.0.1"
}
},
"@actions/github": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-2.1.1.tgz",
"integrity": "sha512-kAgTGUx7yf5KQCndVeHSwCNZuDBvPyxm5xKTswW2lofugeuC1AZX73nUUVDNaysnM9aKFMHv9YCdVJbg7syEyA==",
"requires": {
"@actions/http-client": "^1.0.3",
"@octokit/graphql": "^4.3.1",
"@octokit/rest": "^16.43.1"
}
},
"@actions/http-client": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.7.tgz",
"integrity": "sha512-PY3ys/XH5WMekkHyZhYSa/scYvlE5T/TV/T++vABHuY5ZRgtiBZkn2L2tV5Pv/xDCl59lSZb9WwRuWExDyAsSg==",
"requires": {
"tunnel": "0.0.6"
}
},
"@actions/io": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg=="
},
"@octokit/auth-token": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.0.tgz",
"integrity": "sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==",
"requires": {
"@octokit/types": "^2.0.0"
}
},
"@octokit/endpoint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.0.tgz",
"integrity": "sha512-3nx+MEYoZeD0uJ+7F/gvELLvQJzLXhep2Az0bBSXagbApDvDW0LWwpnAIY/hb0Jwe17A0fJdz0O12dPh05cj7A==",
"requires": {
"@octokit/types": "^2.0.0",
"is-plain-object": "^3.0.0",
"universal-user-agent": "^5.0.0"
},
"dependencies": {
"universal-user-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz",
"integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==",
"requires": {
"os-name": "^3.1.0"
}
}
}
},
"@octokit/graphql": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.3.1.tgz",
"integrity": "sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA==",
"requires": {
"@octokit/request": "^5.3.0",
"@octokit/types": "^2.0.0",
"universal-user-agent": "^4.0.0"
}
},
"@octokit/plugin-paginate-rest": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz",
"integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==",
"requires": {
"@octokit/types": "^2.0.1"
}
},
"@octokit/plugin-request-log": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz",
"integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw=="
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz",
"integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==",
"requires": {
"@octokit/types": "^2.0.1",
"deprecation": "^2.3.1"
}
},
"@octokit/request": {
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.4.tgz",
"integrity": "sha512-qyj8G8BxQyXjt9Xu6NvfvOr1E0l35lsXtwm3SopsYg/JWXjlsnwqLc8rsD2OLguEL/JjLfBvrXr4az7z8Lch2A==",
"requires": {
"@octokit/endpoint": "^6.0.0",
"@octokit/request-error": "^2.0.0",
"@octokit/types": "^2.0.0",
"deprecation": "^2.0.0",
"is-plain-object": "^3.0.0",
"node-fetch": "^2.3.0",
"once": "^1.4.0",
"universal-user-agent": "^5.0.0"
},
"dependencies": {
"universal-user-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz",
"integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==",
"requires": {
"os-name": "^3.1.0"
}
}
}
},
"@octokit/request-error": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.0.tgz",
"integrity": "sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw==",
"requires": {
"@octokit/types": "^2.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/rest": {
"version": "16.43.1",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz",
"integrity": "sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==",
"requires": {
"@octokit/auth-token": "^2.4.0",
"@octokit/plugin-paginate-rest": "^1.1.1",
"@octokit/plugin-request-log": "^1.0.0",
"@octokit/plugin-rest-endpoint-methods": "2.4.0",
"@octokit/request": "^5.2.0",
"@octokit/request-error": "^1.0.2",
"atob-lite": "^2.0.0",
"before-after-hook": "^2.0.0",
"btoa-lite": "^1.0.0",
"deprecation": "^2.0.0",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"lodash.uniq": "^4.5.0",
"octokit-pagination-methods": "^1.1.0",
"once": "^1.4.0",
"universal-user-agent": "^4.0.0"
},
"dependencies": {
"@octokit/request-error": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz",
"integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==",
"requires": {
"@octokit/types": "^2.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
}
}
},
"@octokit/types": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.5.1.tgz",
"integrity": "sha512-q4Wr7RexkPRrkQpXzUYF5Fj/14Mr65RyOHj6B9d/sQACpqGcStkHZj4qMEtlMY5SnD/69jlL9ItGPbDM0dR/dA==",
"requires": {
"@types/node": ">= 8"
}
},
"@types/node": {
"version": "13.11.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.0.tgz",
"integrity": "sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ=="
},
"@zeit/ncc": {
"version": "0.22.1",
"resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.22.1.tgz",
"integrity": "sha512-Qq3bMuonkcnV/96jhy9SQYdh39NXHxNMJ1O31ZFzWG9n52fR2DLtgrNzhj/ahlEjnBziMLGVWDbaS9sf03/fEw==",
"dev": true
},
"atob-lite": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz",
"integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY="
},
"before-after-hook": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz",
"integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A=="
},
"btoa-lite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
"integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc="
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"requires": {
"once": "^1.4.0"
}
},
"execa": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"requires": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
}
},
"get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"requires": {
"pump": "^3.0.0"
}
},
"is-plain-object": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
"integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
"requires": {
"isobject": "^4.0.0"
}
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"isobject": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
"integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA=="
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
"integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
},
"lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
},
"macos-release": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz",
"integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA=="
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"requires": {
"path-key": "^2.0.0"
}
},
"octokit-pagination-methods": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz",
"integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ=="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"os-name": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz",
"integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==",
"requires": {
"macos-release": "^2.2.0",
"windows-release": "^3.1.0"
}
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
},
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"universal-user-agent": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz",
"integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==",
"requires": {
"os-name": "^3.1.0"
}
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "^2.0.0"
}
},
"windows-release": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.0.tgz",
"integrity": "sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ==",
"requires": {
"execa": "^1.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}

View File

@ -0,0 +1,19 @@
{
"name": "publish-release",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "ncc build src/main.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.3",
"@actions/exec": "^1.0.3",
"@actions/github": "^2.1.1"
},
"devDependencies": {
"@zeit/ncc": "^0.22.1"
}
}

View File

@ -0,0 +1,40 @@
const fs = require('fs');
const path = require('path');
const core = require('@actions/core');
const { GitHub, context } = require('@actions/github');
async function run() {
try {
const github = new GitHub(process.env.GITHUB_TOKEN);
const { owner, repo } = context.repo;
const version = core.getInput('version', { required: false });
const draft = false;
const release_id = core.getInput('release_id', { required: false });
const releaseNotesPath = path.join(__dirname, '../../../../release-notes.md');
const releaseNotes = fs.readFileSync(releaseNotesPath, 'utf8');
const regex = new RegExp(
`#####\\s+v${version.replace(/\./g, '\\.')}.*?\n([\\s\\S]*?)\n#####`
);
const body = releaseNotes
.match(regex)[1]
.trim()
.replace(/\s*\n/g, '\n');
console.log(`Updating release with notes:\n${body}`);
await github.repos.updateRelease({
owner,
repo,
release_id,
body,
draft
});
} catch (error) {
core.setFailed(error.message);
}
}
run();

404
.github/actions/scripts/git-restore-mtime.py vendored Executable file
View File

@ -0,0 +1,404 @@
#!/usr/bin/env python3
#
# git-restore-mtime - Change mtime of files based on commit date of last change
#
# Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. See <http://www.gnu.org/licenses/gpl.html>
#
"""
Change the modification time (mtime) of all files in work tree, based on the
date of the most recent commit that modified the file.
Useful prior to generating release tarballs, so each file is archived with a
date that is similar to the date when the file was actually last modified,
assuming the actual modification date and its commit date are close.
By default ignores all ignored and untracked files, and also refuses to work
on trees with uncommitted changes.
"""
# TODO:
# - Add -z on git whatchanged/ls-files so we don't deal with filename decode/OS normalization
# - When Python is bumped to 3.7, use text instead of universal_newlines on subprocess
# - Update "Statistics for some large projects" with modern hardware and repositories.
# - Create a README.md for git-restore-mtime alone. It deserves extensive documentation
# - Move Statistics there
# FIXME:
# - When current dir is outside the worktree, e.g. using --work-tree, `git ls-files`
# assume any relative pathspecs are to worktree root, not the current dir. As such,
# relative pathspecs may not work.
# - Renames and mode changes should not change file mtime:
# - Must check on status 'R100' and mode changes with same blobs
# - Should require status to be (A, C, M, R<100, T). D will never be processed as
# filelist is a subset of lsfileslist.
# - Check file (A, D) for directory mtime is not sufficient:
# - Renames also change dir mtime, unless rename was on a parent dir
# - If most recent change of all files in a dir was a [M]odification,
# dir might not be touched at all.
# - Dirs containing only subdirectories but no direct files will also
# not be touched. They're files' [grand]parent dir, but never their dirname().
# - Some solutions:
# - After files done, perform some dir processing for missing dirs, finding latest
# file (A, D, R)
# - Simple approach: dir mtime is most recent child (dir or file) mtime
# - Use a virtual concept of "created at most at" to fill missing info, bubble up
# to parents and grandparents
# - When handling [grand]parent dirs, stay inside <pathspec>
# - Better handling of merge commits. `-m` is plain *wrong*. `-c/--cc` is perfect, but
# painfully slow. First pass without merge commits is not accurate. Maybe add a new
# `--accurate` mode for `--cc`?
if __name__ != "__main__":
raise ImportError("{} should not be used as a module.".format(__name__))
import subprocess, shlex
import sys, os.path
import logging
import argparse
import time
# Update symlinks only if the OS supports not following them
UPDATE_SYMLINKS = bool(os.utime in getattr(os, 'supports_follow_symlinks', []))
STEPMISSING = 100
# Command-line interface ######################################################
def parse_args():
parser = argparse.ArgumentParser(
description="""Restore original modification time of files based on the date of the
most recent commit that modified them. Useful when generating release tarballs.""")
group = parser.add_mutually_exclusive_group()
group.add_argument('--quiet', '-q', dest='loglevel',
action="store_const", const=logging.WARNING, default=logging.INFO,
help="Suppress informative messages and summary statistics.")
group.add_argument('--verbose', '-v', action="count",
help="Print additional information for each processed file.")
parser.add_argument('--force', '-f', action="store_true",
help="Force execution on trees with uncommitted changes.")
parser.add_argument('--merge', '-m', action="store_true",
help="""Include merge commits. Leads to more recent mtimes and more files per
commit, thus with the same mtime (which may or may not be what you want). Including
merge commits may lead to less commits being evaluated (all files are found sooner),
which improves performance, sometimes substantially. But since merge commits are
usually huge, processing them may also take longer, sometimes substantially.
By default merge logs are only used for files missing from regular commit logs.""")
parser.add_argument('--first-parent', action="store_true",
help="""Consider only the first parent, the "main branch", when parsing merge
commit logs. Only effective when merge commits are included in the log, either
by --merge or to find missing files after first log parse. See --skip-missing.""")
parser.add_argument('--skip-missing', '-s',
action="store_false", default=True, dest="missing",
help="""Do not try to find missing files. If some files were not found in regular
commit logs, by default it re-tries using merge commit logs for these files (if
--merge was not already used). This option disables this behavior, which may slightly
improve performance, but files found only in merge commits will not be updated.""")
parser.add_argument('--no-directories', '-D',
action="store_false", default=True, dest='dirs',
help="""Do not update directory mtime for files created, renamed or deleted in it.
Note: just modifying a file will not update its directory mtime.""")
parser.add_argument('--test', '-t', action="store_true", default=False,
help="Test run: do not actually update any file")
parser.add_argument('--commit-time', '-c',
action='store_true', default=False, dest='commit_time',
help="Use commit time instead of author time")
parser.add_argument('pathspec', nargs='*', metavar='PATH',
help="""Only modify paths matching PATH, directories or files, relative to current
directory. Default is to modify all files handled by git, ignoring untracked files
and submodules.""")
parser.add_argument('--work-tree', dest='workdir',
help="Path to the work tree, if not current directory or one of its parents.")
parser.add_argument('--git-dir', dest='gitdir',
help="Path to the git repository, if not the default <work-tree-root>/.git")
parser.add_argument('--skip-older-than', metavar='SECONDS', type=int,
help="""Do not modify files that are older than %(metavar)s.
It can significantly improve performance if fewer files are processed.
Useful on CI builds, which can eventually switch workspace to different branch,
but mostly performs builds on the same one (e.g. master).
""")
return parser.parse_args()
# Helper functions ############################################################
def setup_logging(args):
TRACE = logging.DEBUG // 2
logging.Logger.trace = lambda _, m, *a, **k: _.log(TRACE, m, *a, **k)
level = (args.verbose and max(TRACE, logging.DEBUG // args.verbose)) or args.loglevel
logging.basicConfig(level=level, format='%(message)s')
return logging.getLogger()
def normalize(path):
"""Normalize paths from git, handling non-ASCII characters.
Git for Windows, as of v1.7.10, stores paths as UTF-8 normalization form C. If path
contains non-ASCII or non-printable chars it outputs the UTF-8 in octal-escaped
notation, double-quoting the whole path. Double-quotes and backslashes are also escaped.
https://git-scm.com/docs/git-config#Documentation/git-config.txt-corequotePath
https://github.com/msysgit/msysgit/wiki/Git-for-Windows-Unicode-Support
https://github.com/git/git/blob/master/Documentation/i18n.txt
Example on git output, this function reverts this:
r'back\slash_double"quote_açaí' -> r'"back\\slash_double\"quote_a\303\247a\303\255"'
"""
if path and path[0] == '"':
# Python 2: path = path[1:-1].decode("string-escape")
# Python 3: https://stackoverflow.com/a/46650050/624066
path = (path[1:-1] # Remove enclosing double quotes
.encode('latin1') # Convert to bytes, required 'unicode-escape'
.decode('unicode-escape') # Perform the actual octal-escaping decode
.encode('latin1') # 1:1 mapping to bytes, forming UTF-8 encoding
.decode('utf8')) # Decode from UTF-8
# Make sure the slash matches the OS; for Windows we need a backslash
return os.path.normpath(path)
if UPDATE_SYMLINKS:
def touch(path, mtime, test=False):
"""The actual mtime update"""
if test: return
os.utime(path, (mtime, mtime), follow_symlinks=False)
else:
def touch(path, mtime, test=False):
"""The actual mtime update"""
if test: return
os.utime(path, (mtime, mtime))
def isodate(secs):
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(secs))
# Git class and parselog(), the heart of the script ###########################
class Git():
def __init__(self, workdir=None, gitdir=None):
self.gitcmd = ['git']
if workdir: self.gitcmd.extend(('--work-tree', workdir))
if gitdir : self.gitcmd.extend(('--git-dir', gitdir))
self.workdir, self.gitdir = self._repodirs()
def ls_files(self, pathlist=None):
return (normalize(_) for _ in self._run('ls-files --full-name', pathlist))
def is_dirty(self):
return bool(self._run('diff --no-ext-diff --quiet', output=False))
def log(self, merge=False, first_parent=False, commit_time=False, pathlist=None):
cmd = 'whatchanged --pretty={}'.format('%ct' if commit_time else '%at')
if merge: cmd += ' -m'
if first_parent: cmd += ' --first-parent'
return self._run(cmd, pathlist)
def _repodirs(self):
return (os.path.normpath(_) for _ in
self._run('rev-parse --show-toplevel --absolute-git-dir', check=True))
def _run(self, cmdstr, pathlist=None, output=True, check=False):
cmdlist = self.gitcmd + shlex.split(cmdstr)
if pathlist:
cmdlist.append('--')
cmdlist.extend(pathlist)
log.trace("Executing: %s", ' '.join(cmdlist))
if not output:
return subprocess.call(cmdlist)
if check:
try:
stdout = subprocess.check_output(cmdlist, universal_newlines=True)
return stdout.splitlines()
except subprocess.CalledProcessError as e:
raise self.Error(e.returncode, e.cmd, e.output, e.stderr)
self.proc = subprocess.Popen(cmdlist, stdout=subprocess.PIPE, universal_newlines=True)
return (_.strip() for _ in self.proc.stdout)
class Error(subprocess.CalledProcessError): pass
def parselog(filelist, dirlist, stats, git, merge=False, filterlist=None):
mtime = 0
for line in git.log(merge, args.first_parent, args.commit_time, filterlist):
stats['loglines'] += 1
# Blank line between Date and list of files
if not line: continue
# File line
if line[0] == ':': # Faster than line.startswith(':')
# If line describes a rename, linetok has three tokens, otherwise two
linetok = line.split('\t')
status = linetok[0]
file = linetok[-1]
# Handles non-ASCII chars and OS path separator
file = normalize(file)
if file in filelist:
stats['files'] -= 1
log.debug("%d\t%d\t%d\t%s\t%s",
stats['loglines'], stats['commits'], stats['files'],
isodate(mtime), file)
filelist.remove(file)
try:
touch(os.path.join(git.workdir, file), mtime, args.test)
stats['touches'] += 1
except Exception as e:
log.error("ERROR: %s", e)
stats['errors'] += 1
if args.dirs:
dirname = os.path.dirname(file)
if status[-1] in ('A', 'D') and dirname in dirlist:
log.debug("%d\t%d\t-\t%s\t%s",
stats['loglines'], stats['commits'],
isodate(mtime), "{}/".format(dirname or '.'))
dirlist.remove(dirname)
try:
touch(os.path.join(git.workdir, dirname), mtime, args.test)
stats['dirtouches'] += 1
except Exception as e:
log.error("ERROR: %s", e)
stats['direrrors'] += 1
# Date line
else:
stats['commits'] += 1
mtime = int(line)
# All files done?
if not stats['files']:
git.proc.terminate() # hackish, but does the job. Not needed anyway
return
# Main Logic ##################################################################
def main():
start = time.time() # yes, Wall time. CPU time is not realistic for users.
stats = {_: 0 for _ in ('loglines', 'commits', 'touches', 'errors', 'dirtouches', 'direrrors')}
# First things first: Where and Who are we?
try:
git = Git(args.workdir, args.gitdir)
except Git.Error as e:
# Not in a git repository, and git already informed user on stderr. So we just...
return e.returncode
# Do not work on dirty repositories, unless --force
if not args.force and git.is_dirty():
log.critical(
"ERROR: There are local changes in the working directory.\n"
"This could lead to undesirable results for modified files.\n"
"Please, commit your changes (or use --force) and try again.\n"
"Aborting")
return 1
# Get the files managed by git and build file and dir list to be processed
filelist = set()
dirlist = set()
if UPDATE_SYMLINKS and not args.skip_older_than:
filelist = set(git.ls_files(args.pathspec))
dirlist = set(os.path.dirname(_) for _ in filelist)
else:
for path in git.ls_files(args.pathspec):
fullpath = os.path.join(git.workdir, path)
# Symlink (to file, to dir or broken - git handles the same way)
if not UPDATE_SYMLINKS and os.path.islink(fullpath):
log.warning("WARNING: Skipping symlink, OS does not support update: %s", path)
continue
# skip files which are older than given threshold
if args.skip_older_than and start - os.path.getmtime(fullpath) > args.skip_older_than:
continue
# Always add them relative to worktree root
filelist.add(path)
dirlist.add(os.path.dirname(path))
stats['totalfiles'] = stats['files'] = len(filelist)
log.info("{0:,} files to be processed in work dir".format(stats['totalfiles']))
if not filelist:
# Nothing to do. Exit silently and without errors, just like git does
return
# Process the log until all files are 'touched'
log.debug("Line #\tLog #\tF.Left\tModification Time\tFile Name")
parselog(filelist, dirlist, stats, git, args.merge, args.pathspec)
# Missing files
if filelist:
# Try to find them in merge logs, if not done already
# (usually HUGE, thus MUCH slower!)
if args.missing and not args.merge:
filterlist = list(filelist)
for i in range(0, len(filterlist), STEPMISSING):
parselog(filelist, dirlist, stats, git,
merge=True, filterlist=filterlist[i:i+STEPMISSING])
# Still missing some?
for file in filelist:
log.warning("WARNING: not found in log: %s", file)
# Final statistics
# Suggestion: use git-log --before=mtime to brag about skipped log entries
log.info(
"Statistics:\n"
"{:13,.2f} seconds\n"
"{:13,} log lines processed\n"
"{:13,} commits evaluated"
"".format(time.time()-start, stats['loglines'], stats['commits']))
if args.dirs:
if stats['direrrors']: log.info("{:13,} directory update errors".format(stats['direrrors']))
log.info("{:13,} directories updated".format(stats['dirtouches']))
if stats['touches'] != stats['totalfiles']: log.info("{:13,} files".format(stats['totalfiles']))
if stats['files']: log.info("{:13,} files missing".format(stats['files']))
if stats['errors']: log.info("{:13,} file update errors".format(stats['errors']))
log.info("{:13,} files updated".format(stats['touches']))
if args.test:
log.info("TEST RUN - No files modified!")
args = parse_args()
log = setup_logging(args)
log.trace("Arguments: %s", args)
# UI done, it's show time!
try:
sys.exit(main())
except KeyboardInterrupt:
log.info("Aborting")
sys.exit(-1)

496
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,496 @@
name: Build
on:
push:
tags: [ '*' ]
jobs:
web:
runs-on: ubuntu-latest
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-tag@v2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- uses: actions/checkout@v2
with:
repository: keeweb/keeweb
# ref: develop
- name: Install npm modules
run: npm ci
- name: Test
run: npm test
- name: Grunt
run: grunt
- name: Upload artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
linux:
runs-on: ubuntu-latest
needs:
- web
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-tag@v2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- uses: actions/checkout@v2
with:
repository: keeweb/keeweb
# ref: develop
- name: Download artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
- name: Write secrets
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
KEEWEB_SIGN: ${{ secrets.KEEWEB_SIGN }}
run: |
mkdir keys
echo "$PRIVATE_KEY" > keys/private-key.pem
echo "$KEEWEB_SIGN" > keys/keeweb-sign.json
- name: Build in Docker
uses: ./.github/actions/linux-build
- name: Upload AppImage artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
- name: Upload snap artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
- name: Upload deb artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
- name: Upload zip artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
- name: Upload rpm artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
- name: Upload update artifact
uses: actions/upload-artifact@v1
with:
name: UpdateDesktop.zip
path: dist/desktop/UpdateDesktop.zip
darwin:
runs-on: macos-latest
needs:
- web
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-tag@v2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- uses: actions/checkout@v2
with:
repository: keeweb/keeweb
# ref: develop
- name: Download artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
- name: Install npm modules
run: npm ci
- name: Install desktop npm modules
working-directory: desktop
run: npm ci
- name: Install grunt
run: sudo npm i -g grunt-cli
- name: Write secrets
env:
CODESIGN: ${{ secrets.CODESIGN }}
APPLE_DEPLOY_PASSWORD: ${{ secrets.APPLE_DEPLOY_PASSWORD }}
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
run: |
mkdir keys
echo "$CODESIGN" > keys/codesign.json
xcrun altool --store-password-in-keychain-item "AC_PASSWORD" -u "$APPLE_ID_USERNAME" -p "$APPLE_DEPLOY_PASSWORD"
- uses: keeweb/import-codesign-certs@v1
with:
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- name: Grunt
run: grunt desktop-darwin
- name: Upload dmg artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.dmg
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.dmg
win32:
runs-on: windows-latest
needs:
- web
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-tag@v2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- uses: actions/checkout@v2
with:
repository: 'keeweb/keeweb'
# ref: 'develop'
- name: Download artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: dist
- name: Install npm modules
run: npm ci
- name: Install desktop npm modules
working-directory: desktop
run: npm ci
- name: Install grunt
run: npm i -g grunt-cli
- name: Write secrets
env:
CODESIGN: ${{ secrets.CODESIGN }}
MS_CODESIGN_PRIVATE_KEY_CLIENT: ${{ secrets.MS_CODESIGN_PRIVATE_KEY_CLIENT }}
MS_CODESIGN_PUBLIC_KEY_CLIENT: ${{ secrets.MS_CODESIGN_PUBLIC_KEY_CLIENT }}
MS_CODESIGN_PUBLIC_KEY_SERVER: ${{ secrets.MS_CODESIGN_PUBLIC_KEY_SERVER }}
run: |
mkdir keys
echo $Env:CODESIGN > keys/codesign.json
mkdir keys/code-signing
echo $Env:MS_CODESIGN_PRIVATE_KEY_CLIENT > keys/code-signing/private-key-client.pem
echo $Env:MS_CODESIGN_PUBLIC_KEY_CLIENT > keys/code-signing/public-key-client.pem
echo $Env:MS_CODESIGN_PUBLIC_KEY_SERVER > keys/code-signing/public-key-server.pem
- name: Grunt
run: grunt desktop-win32
- name: Upload ia32 exe artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
- name: Upload ia32 zip artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
- name: Upload x64 exe artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
- name: Upload x64 zip artifact
uses: actions/upload-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
path: dist/desktop/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
publish:
runs-on: ubuntu-latest
needs:
- linux
- darwin
- win32
steps:
- name: Get current git tag
id: get_tag
uses: keeweb/get-tag@v2
with:
tagRegex: "^v(\\d+\\.\\d+\\.\\d+)$"
tagRegexGroup: 1
- uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
with:
version: '285.0.0'
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true
- uses: actions/checkout@v2
with:
repository: keeweb/keeweb
path: keeweb
# ref: develop
- name: Install npm modules
working-directory: keeweb
run: npm ci
- name: Download html artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html
path: html
- name: Download linux.AppImage artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
path: assets
- name: Download linux.snap artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
path: assets
- name: Download linux.deb artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
path: assets
- name: Download linux.zip artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
path: assets
- name: Download linux.rpm artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
path: assets
- name: Download darwin.dmg artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.dmg
path: assets
- name: Download win32.ia32.exe artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
path: assets
- name: Download win32.ia32.zip artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
path: assets
- name: Download win32.x64.exe artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
path: assets
- name: Download win32.x64.zip artifact
uses: actions/download-artifact@v1
with:
name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
path: assets
- name: Download update artifact
uses: actions/download-artifact@v1
with:
name: UpdateDesktop.zip
path: assets
- name: Zip html
working-directory: html
run: zip -vr ../assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.html.zip .
- name: Copy assets to dist
run: mkdir -p keeweb/dist/desktop && cp assets/* keeweb/dist/desktop
- name: Write secrets
env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
KEEWEB_SIGN: ${{ secrets.KEEWEB_SIGN }}
working-directory: keeweb
run: |
mkdir keys
echo "$PRIVATE_KEY" > keys/private-key.pem
echo "$KEEWEB_SIGN" > keys/keeweb-sign.json
- name: Grunt
working-directory: keeweb
run: grunt finish-release
- name: Copy signatures to assets
run: cp keeweb/dist/desktop/Verify.sign.sha256 assets
- name: Copy checksums to assets
run: cp keeweb/dist/desktop/Verify.sha256 assets
- name: Login to DockerHub Registry
env:
DOCKERHUB_ACCESS_TOKEN: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
run: echo $DOCKERHUB_ACCESS_TOKEN | docker login -u $DOCKERHUB_USERNAME --password-stdin
- name: Copy dist to the Docker context
run: cp -r html keeweb/package/docker/dist
- name: Build the Docker image
working-directory: keeweb
run: docker build -t antelle/keeweb:latest package/docker
- name: Tag the Docker image
run: docker tag antelle/keeweb:latest antelle/keeweb:${{ steps.get_tag.outputs.tag }}
- name: Push the Docker image to the registry
run: docker push antelle/keeweb
- name: Create a GitHub release
id: create_release
uses: actions/create-release@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Desktop apps v${{ steps.get_tag.outputs.tag }}
draft: true
prerelease: false
- name: Upload html asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.html.zip
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.html.zip
asset_content_type: application/octet-stream
- name: Upload linux.AppImage asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.AppImage
asset_content_type: application/octet-stream
- name: Upload linux.snap asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.snap
asset_content_type: application/octet-stream
- name: Upload linux.deb asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.deb
asset_content_type: application/octet-stream
- name: Upload linux.zip asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x64.zip
asset_content_type: application/octet-stream
- name: Upload linux.rpm asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.linux.x86_64.rpm
asset_content_type: application/octet-stream
- name: Upload darwin.dmg asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.dmg
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.mac.dmg
asset_content_type: application/octet-stream
- name: Upload win32.ia32.exe asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.exe
asset_content_type: application/octet-stream
- name: Upload win32.ia32.zip asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.ia32.zip
asset_content_type: application/octet-stream
- name: Upload win32.x64.exe asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.exe
asset_content_type: application/octet-stream
- name: Upload win32.x64.zip asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
asset_name: KeeWeb-${{ steps.get_tag.outputs.tag }}.win.x64.zip
asset_content_type: application/octet-stream
- name: Upload update asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/UpdateDesktop.zip
asset_name: UpdateDesktop.zip
asset_content_type: application/octet-stream
- name: Upload verify.sign asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/Verify.sign.sha256
asset_name: Verify.sign.sha256
asset_content_type: application/octet-stream
- name: Upload verify.sha asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: assets/Verify.sha256
asset_name: Verify.sha256
asset_content_type: application/octet-stream
- name: Publish the GitHub release
uses: ./keeweb/.github/actions/publish-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
version: ${{ steps.get_tag.outputs.tag }}
release_id: ${{ steps.create_release.outputs.id }}
- name: Checkout gh-pages
uses: actions/checkout@v2
with:
ref: gh-pages
path: gh-pages
fetch-depth: 0
- name: Commit dist to gh-pages
working-directory: gh-pages
run: |
git rm -r '*'
cp -r ../html/* .
mkdir -p .github/workflows
echo $GITHUB_SHA > build.txt
date >> build.txt
git add .
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git commit -am v${{ steps.get_tag.outputs.tag }}
- name: Push gh-pages
uses: keeweb/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
directory: gh-pages
- name: Restore git mtime
working-directory: gh-pages
run: python3 ../keeweb/.github/actions/scripts/git-restore-mtime.py
- name: Sync the website
run: gsutil -m rsync -r -d -x "^\." gh-pages gs://app.keeweb.info/

View File

@ -13,7 +13,6 @@ jobs:
- uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
with:
version: '285.0.0'
service_account_email: ${{ secrets.GCP_SA_EMAIL }}
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true
- name: Restore git mtime

2
.gitignore vendored
View File

@ -3,7 +3,7 @@ misc.xml
.DS_Store
node_modules/
*.log
dist/
/dist/
tmp/
coverage/
keys

View File

@ -579,8 +579,8 @@ module.exports = function(grunt) {
'sign-exe': {
options: {
url: pkg.homepage,
get vm() {
return getCodeSingConfig().windowsVM;
get windows() {
return getCodeSingConfig().windows;
},
get certHash() {
return getCodeSingConfig().microsoftCertHash;

View File

@ -33,6 +33,7 @@ class FileModel extends Model {
if (keyFileData) {
kdbxweb.ByteUtils.zeroBuffer(keyFileData);
}
this.fixVersion();
logger.info(
'Opened file ' +
this.name +
@ -250,6 +251,17 @@ class FileModel extends Model {
});
}
fixVersion() {
if (
this.db.meta.generator === 'KdbxWeb' &&
this.db.header.versionMajor === 4 &&
this.db.header.versionMinor === 1
) {
this.db.header.versionMinor = 0;
logger.info('Fixed file version: 4.1 => 4.0');
}
}
reload() {
this.buildObjectMap();
this.readModel();

View File

@ -1,74 +1,70 @@
/**
* This will require the latest (unreleased) version of `osslsigncode` with pkcs11 patch
* Build it like this:
*
* curl -L http://sourceforge.net/projects/osslsigncode/files/osslsigncode/osslsigncode-1.7.1.tar.gz/download -o osslsigncode.tar.gz
* tar -zxvf osslsigncode.tar.gz
* git clone https://git.code.sf.net/p/osslsigncode/osslsigncode osslsigncode-master
* cp osslsigncode-master/osslsigncode.c osslsigncode-1.7.1/osslsigncode.c
* rm osslsigncode.tar.gz
* rm -rf osslsigncode-master
* cd osslsigncode-1.7.1/
* export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig
* ./configure
* make
* sudo cp osslsigncode /usr/local/bin/osslsigncode
*
* Install this:
* brew install opensc
* brew install engine_pkcs11
*
* https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Signing_an_executable_with_Authenticode
*/
const fs = require('fs');
const path = require('path');
const { spawnSync } = require('child_process');
const AdmZip = require('adm-zip');
const { runRemoteTask } = require('run-remote-task');
module.exports = function(grunt) {
grunt.registerMultiTask('sign-exe', 'Signs exe file with authenticode certificate', function() {
const opt = this.options();
for (const [file, name] of Object.entries(opt.files)) {
signFile(file, name, opt);
}
});
grunt.registerMultiTask(
'sign-exe',
'Signs exe file with authenticode certificate',
async function() {
const done = this.async();
const opt = this.options();
for (const [file, name] of Object.entries(opt.files)) {
await signFile(file, name, opt);
}
done();
}
);
async function signFile(file, name, opt) {
grunt.log.writeln(`Signing ${file}...`);
function signFile(file, name, opt) {
const fileNameWithoutFolder = path.basename(file);
const sharePath = `${process.env.HOME}/VMShare/${fileNameWithoutFolder}`;
fs.copyFileSync(file, sharePath);
const timeServer = 'http://timestamp.verisign.com/scripts/timstamp.dll';
const actionConfig = {
exe: fileNameWithoutFolder,
name: name || fileNameWithoutFolder,
url: opt.url
};
const cmd = 'VBoxManage';
const args = [
'guestcontrol',
opt.vm.name,
'--username',
opt.vm.user,
'--password',
opt.vm.pass,
'run',
opt.vm.exec,
`sign /t ${timeServer} /d "${name}" /du ${opt.url} ${opt.vm.share}${fileNameWithoutFolder}`
];
// the algo is not working: "/fd ${opt.algo}"
let res = spawnSync(cmd, args);
if (res.status) {
args[5] = '*';
const cmdStr = cmd + ' ' + args.join(' ');
grunt.warn(`Sign error ${file}: exit code ${res.status}.\nCommand: ${cmdStr}`);
}
res = spawnSync('osslsigncode', ['verify', sharePath]);
if (res.status) {
const hasCertHash = res.stdout.includes(`Serial : ${opt.certHash}`);
if (!hasCertHash) {
const zip = new AdmZip();
zip.addFile('action.json', Buffer.from(JSON.stringify(actionConfig)));
zip.addLocalFile(file);
const zipContents = zip.toBuffer();
fs.writeFileSync('data.zip', zipContents);
try {
const taskResult = await runRemoteTask(opt.windows, zipContents);
const signedFile = taskResult.file;
const signtool =
'C:\\Program Files (x86)\\Windows Kits\\10\\App Certification Kit\\signtool.exe';
const res = spawnSync(signtool, ['verify', '/pa', '/v', signedFile]);
if (res.status) {
grunt.warn(
`Verify error ${file}: exit code ${res.status}.\n${res.stdout.toString()}`
);
}
if (!res.stdout.includes('Successfully verified')) {
grunt.warn(`Verify error ${file}:\n${res.stdout.toString()}`);
}
if (!res.stdout.includes(opt.certHash)) {
grunt.warn(`Verify error ${file}: expected hash was not found`);
}
fs.unlinkSync(signedFile, file);
fs.writeFileSync(file, taskResult.data);
grunt.log.writeln(`Signed ${file}: ${name}`);
} catch (e) {
grunt.warn(`Sign error ${file}: ${e}`);
}
fs.renameSync(sharePath, file);
grunt.log.writeln(`Signed ${file}: ${name}`);
}
};

View File

@ -52,6 +52,11 @@ module.exports = function(grunt) {
'build-desktop-dist-win32'
]);
// prettier-ignore
grunt.registerTask('finish-release', 'Complete the release started with desktop-*', [
'sign-dist'
]);
// prettier-ignore
grunt.registerTask('cordova', 'Build cordova app', [
'default',

20
package-lock.json generated
View File

@ -1555,6 +1555,11 @@
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz",
"integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ=="
},
"adm-zip": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz",
"integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g=="
},
"agent-base": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
@ -12380,6 +12385,21 @@
"aproba": "^1.1.1"
}
},
"run-remote-task": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/run-remote-task/-/run-remote-task-0.3.0.tgz",
"integrity": "sha512-8dEOgb1wAXvWeCsQFUq6t3NgbUSO0Im78m4QTT1be0lkeYsU26R0kFGdbS/jvoBb0u5Q+MyuBOdZtgum6oyGhg==",
"requires": {
"minimist": "^1.2.5"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
},
"rxjs": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz",

View File

@ -14,6 +14,7 @@
"@babel/plugin-external-helpers": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/preset-env": "^7.9.0",
"adm-zip": "^0.4.14",
"argon2-browser": "1.13.0",
"autoprefixer": "^9.7.5",
"babel-cli": "^6.26.0",
@ -77,6 +78,7 @@
"prettier": "^1.19.1",
"puppeteer": "^2.1.1",
"raw-loader": "^4.0.0",
"run-remote-task": "^0.3.0",
"sass-loader": "^8.0.2",
"stats-webpack-plugin": "0.7.0",
"string-replace-webpack-plugin": "0.1.3",

View File

@ -37,16 +37,14 @@ ADD keeweb.conf /etc/nginx/conf.d/keeweb.conf
RUN wget https://github.com/keeweb/keeweb/archive/gh-pages.zip; \
unzip gh-pages.zip; \
rm gh-pages.zip; \
mv keeweb-gh-pages keeweb; \
rm keeweb/CNAME
mv keeweb-gh-pages keeweb;
# clone keeweb plugins
RUN wget https://github.com/keeweb/keeweb-plugins/archive/master.zip; \
unzip master.zip; \
rm master.zip; \
mv keeweb-plugins-master/docs keeweb/plugins; \
rm -rf keeweb-plugins-master \
rm keeweb/plugins/CNAME
rm -rf keeweb-plugins-master;
ADD entrypoint.sh /opt/entrypoint.sh
RUN chmod a+x /opt/entrypoint.sh

View File

@ -17,7 +17,7 @@ FROM nginx:stable
LABEL maintainer="antelle.net@gmail.com"
# install
RUN apt-get -y update && apt-get -y install openssl wget unzip
RUN apt-get -y update && apt-get -y install openssl curl unzip
# setup nginx
RUN rm -rf /etc/nginx/conf.d/*; \
@ -32,20 +32,17 @@ ADD keeweb.conf /etc/nginx/conf.d/keeweb.conf
ADD entrypoint.sh /opt/entrypoint.sh
RUN chmod a+x /opt/entrypoint.sh
# clone keeweb
RUN wget https://github.com/keeweb/keeweb/archive/gh-pages.zip; \
unzip gh-pages.zip; \
rm gh-pages.zip; \
mv keeweb-gh-pages keeweb; \
rm keeweb/CNAME
# add keeweb files
ADD dist keeweb
# clone keeweb plugins
RUN wget https://github.com/keeweb/keeweb-plugins/archive/master.zip; \
RUN curl -Ss -L -O https://github.com/keeweb/keeweb-plugins/archive/master.zip; \
unzip master.zip; \
rm master.zip; \
mv keeweb-plugins-master/docs keeweb/plugins; \
rm -rf keeweb-plugins-master \
rm keeweb/plugins/CNAME
rm -rf keeweb-plugins-master;
RUN apt-get -y remove curl unzip
ENTRYPOINT ["/opt/entrypoint.sh"]
CMD ["nginx"]

View File

@ -1,5 +1,10 @@
Release notes
-------------
##### v1.13.2 (TBD)
`+` files previously created as v4.1 will be written as v4.0
`+` fixed Docker build
`*` builds are now run on CI
##### v1.13.1 (2020-04-04)
`-` fix #1444: fixed website favicons and attached images
`-` fix #1445: fixed offline mode in Chrome and Firefox