Skip to content

Commit

Permalink
feat: adding workflow for apt release (#320)
Browse files Browse the repository at this point in the history
* updating workflow for apt release
  • Loading branch information
kridai authored Nov 16, 2021
1 parent ece2b9f commit bdfab17
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 0 deletions.
121 changes: 121 additions & 0 deletions .github/scripts/pack-debian-apt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const qq = require('qqjs');
const pjson = require(`${process.cwd()}/package.json`);
const fs = require('fs');


function debArch(arch) {
if (arch === 'x64') return 'amd64';
if (arch === 'arm') return 'armel'
throw new Error(`invalid arch: ${arch}`);
}

const scripts = {
bin: () => `#!/usr/bin/env bash
set -e
echoerr() { echo "$@" 1>&2; }
get_script_dir () {
SOURCE="\${BASH_SOURCE[0]}"
# While \$SOURCE is a symlink, resolve it
while [ -h "\$SOURCE" ]; do
DIR="\$( cd -P "\$( dirname "\$SOURCE" )" && pwd )"
SOURCE="\$( readlink "\$SOURCE" )"
# If \$SOURCE was a relative symlink (so no "/" as prefix, need to resolve it relative to the symlink base directory
[[ \$SOURCE != /* ]] && SOURCE="\$DIR/\$SOURCE"
done
DIR="\$( cd -P "\$( dirname "\$SOURCE" )" && pwd )"
echo "\$DIR"
}
DIR=\$(get_script_dir)
export ${('UPDATE_INSTRUCTIONS')}="update with \\"sudo apt update && sudo apt install ${pjson.oclif.bin}\\""
\$DIR/node \$DIR/run "\$@"
`,
control: (arch, debVersion) => `Package: ${pjson.oclif.bin}
Version: ${debVersion}
Section: main
Priority: standard
Architecture: ${arch}
Maintainer: ${pjson.author}
Description: ${pjson.description}
`,
ftparchive: () => `
APT::FTPArchive::Release::Origin "${pjson.author}";
APT::FTPArchive::Release::Suite "stable";
}
`,
postinst: () => `#!/usr/bin/env bash
cd /usr/lib/twilio-cli
eval $(node -p "require('./package').scripts.postinstall")
`
}


const packDebian = async (arch) => {
const description = 'pack Twilio CLI into debian package'
const rootDir = process.cwd();
const config = {
bin: pjson.oclif.bin,
dirname: pjson.name
}

if (process.platform !== 'linux') throw new Error('must be run from linux')
const debVersion = `${pjson.version.split('-')[0]}-1`;
//twilio-cli/dist/deb
const dist = qq.join(rootDir, 'dist','deb');
await qq.rm(dist);
await qq.mkdirp(dist);
const build = async (arch) => {
// example 'twilio_2.32.1-1_amd64'
const versionedDebBase = `twilio_${debVersion}_${debArch(arch)}`;
// 'twilio-cli/tmp/apt/twilio_2.32.1-1_amd64.apt'
const workspace = qq.join(rootDir, 'tmp', 'apt', `${versionedDebBase}.apt`);
await qq.rm(workspace);
await qq.mkdirp([workspace, 'DEBIAN']);
await qq.mkdirp([workspace, 'usr/bin']);
await qq.mkdirp([workspace, 'usr/lib']);
await qq.mkdirp([dist, debArch(arch)]);
await qq.cp([rootDir,'tmp',`linux-${arch}`, pjson.oclif.bin], [workspace, 'usr/lib', pjson.name]);
await qq.write([workspace, 'usr/lib', config.dirname, 'bin', config.bin], scripts.bin(config));
await qq.write([workspace, 'DEBIAN/control'], scripts.control(debArch(arch), debVersion));
await qq.write([workspace, 'DEBIAN/postinst'], scripts.postinst());
// making files executable
await qq.chmod([workspace, 'usr/lib', config.dirname, 'bin', config.bin], 0o755);
await qq.chmod([workspace, 'DEBIAN/postinst'], 0o755);
await qq.x(`ln -s "../lib/${config.dirname}/bin/${config.bin}" "${workspace}/usr/bin/${pjson.oclif.bin}"`);
await qq.x(`dpkg --build "${workspace}" "${qq.join(dist, debArch(arch), `${versionedDebBase}.deb`)}"`);
}
for (const a of arch) {
await build(a);
await qq.x(`apt-ftparchive packages ${debArch(a)}/ >> Packages`, {cwd: dist});
}
await qq.x('gzip -c Packages > Packages.gz', {cwd: dist});
await qq.x('bzip2 -k Packages', {cwd: dist});
await qq.x('xz -k Packages', {cwd: dist});
const ftparchive = qq.join(rootDir, 'tmp', 'apt', 'apt-ftparchive.conf');
await qq.write(ftparchive, scripts.ftparchive(config));
await qq.x(`apt-ftparchive -c "${ftparchive}" release . > Release`, {cwd: dist});
const gpgKey = process.env.GPG_SIGNING_KEY_ID;
const passphrase = process.env.GPG_SIGNING_KEY_PASSPHRASE;
if (gpgKey) {
await qq.x(`gpg --digest-algo SHA512 --clearsign -u ${gpgKey} --batch --pinentry-mode loopback --passphrase ${passphrase} -o InRelease Release`, {cwd: dist});
await qq.x(`gpg --digest-algo SHA512 -abs -u ${gpgKey} --batch --pinentry-mode loopback --passphrase ${passphrase} -o Release.gpg Release`, {cwd: dist});
}
await qq.x(`aws s3 cp ${dist} s3://${pjson.oclif.update.s3.bucket}/apt --recursive --acl public-read`);
}
// importing secret key
const importGPG = async() => {
let key = process.env.GPG_SIGNING_KEY;
const buff = Buffer.from(key, 'base64');
key = buff.toString("utf8");
const keyPath = `key.pgp`;
fs.writeFileSync(keyPath, key);
await qq.x(`gpg --import --batch --yes ${keyPath}`);
}

(async () => {
importGPG();
const archStr = process.argv[2];
const arches = archStr.split(",");
await packDebian(arches);
})();


57 changes: 57 additions & 0 deletions .github/workflows/apt-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Apt Release
on:
workflow_dispatch:
workflow_run:
# wait for Cli Release to complete, when it completes, start this workflow
workflows: ["Cli Release"]
branches: [main]
types:
- completed

jobs:
apt-build-release:
runs-on: ubuntu-latest

steps:
- name: Check Out Repo
uses: actions/checkout@v2

- name: Configure AWS credentials from Test account
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
aws-region: us-east-1

- name: generate linux tarball
run: |
npm cache clear & npm install
npm install -g @oclif/dev-cli
oclif-dev pack -t linux-x64,linux-arm
- name: Build Deb Package
env:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY}}
GPG_SIGNING_KEY_ID: ${{ secrets.GPG_SIGNING_KEY_ID }}
GPG_SIGNING_KEY_PASSPHRASE: ${{ secrets.GPG_SIGNING_KEY_PASSPHRASE }}
run: |
node .github/scripts/pack-debian-apt.js x64,arm
notify-complete-fail:
if: ${{ failure() || cancelled() }}
needs: [ apt-build-release ]
name: Notify Release Failed
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.ALERT_SLACK_WEB_HOOK }}
SLACK_COLOR: "#ff3333"
SLACK_USERNAME: CLI Release Bot
SLACK_ICON_EMOJI: ":ship:"
SLACK_TITLE: "Twilio Cli"
SLACK_MESSAGE: 'APT Release Failed'
MSG_MINIMAL: actions url

0 comments on commit bdfab17

Please sign in to comment.