├── LICENSE ├── .github └── workflows │ ├── update-checker.yml │ ├── dispatch.yml │ └── build.yml ├── README-EN.md └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 P3TERX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/update-checker.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019-2021 P3TERX 3 | # 4 | # This is free software, licensed under the MIT License. 5 | # See /LICENSE for more information. 6 | # 7 | # https://github.com/P3TERX/Actions-OpenWrt 8 | # File: .github/workflows/update-checker.yml 9 | # Description: Source code update checker 10 | # 11 | 12 | name: Update Checker 13 | 14 | env: 15 | REPO_URL: https://github.com/coolsnowwolf/lede 16 | REPO_BRANCH: master 17 | 18 | on: 19 | workflow_dispatch: 20 | # schedule: 21 | # - cron: 0 */18 * * * 22 | 23 | jobs: 24 | check: 25 | runs-on: ubuntu-latest 26 | 27 | steps: 28 | 29 | - name: Get Commit Hash 30 | id: getHash 31 | run: | 32 | git clone --depth 1 $REPO_URL -b $REPO_BRANCH . 33 | echo "::set-output name=commitHash::$(git rev-parse HEAD)" 34 | 35 | - name: Compare Commit Hash 36 | id: cacheHash 37 | uses: actions/cache@v2 38 | with: 39 | path: .commitHash 40 | key: HEAD-${{ steps.getHash.outputs.commitHash }} 41 | 42 | - name: Save New Commit Hash 43 | if: steps.cacheHash.outputs.cache-hit != 'true' 44 | run: | 45 | echo ${{ steps.getHash.outputs.commitHash }} | tee .commitHash 46 | 47 | - name: Trigger build 48 | if: steps.cacheHash.outputs.cache-hit != 'true' 49 | uses: peter-evans/repository-dispatch@v1 50 | with: 51 | token: ${{ secrets.ACTIONS_TRIGGER_PAT }} 52 | event-type: Source Code Update 53 | 54 | - name: Delete workflow runs 55 | uses: GitRML/delete-workflow-runs@main 56 | with: 57 | retain_days: 2 58 | keep_minimum_runs: 2 59 | -------------------------------------------------------------------------------- /.github/workflows/dispatch.yml: -------------------------------------------------------------------------------- 1 | name: Repo Dispatcher 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | target: 6 | description: 'dev1,dev2' 7 | required: false 8 | default: 'x86_64' 9 | 10 | jobs: 11 | set_matrix: 12 | runs-on: ubuntu-latest 13 | outputs: 14 | device: ${{ steps.set_matrix.outputs.matrix }} 15 | #event_inputs_json: ${{ steps.set_matrix.outputs.matrix }} 16 | name: "set matrix for: ${{ github.event.inputs.target }}" 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@main 20 | - name: prinf info 21 | id: set_matrix 22 | run: | 23 | if [ -z "${{ github.event.inputs.target }}" ];then 24 | matrix=$(find build/ -maxdepth 2 -type f -name set_matrix.sh | awk -F/ '{print $2}' | paste -s - -d ',') 25 | else 26 | matrix=${{ github.event.inputs.target }} 27 | fi 28 | echo '::set-output name=matrix::["'${matrix}'"]' 29 | echo 'name=matrix: ["'${matrix}'"]' 30 | build: 31 | runs-on: ubuntu-latest 32 | needs: set_matrix 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | device: ${{ fromJson(needs.set_matrix.outputs.device) }} 37 | steps: 38 | - name: Trigger Compile 39 | run: | 40 | branch=${GITHUB_REF##*/}; 41 | curl \ 42 | -X POST https://api.github.com/repos/${{ github.repository }}/dispatches \ 43 | -H "Accept: application/vnd.github.everest-preview+json" \ 44 | -H "Authorization: token ${{ secrets.gh_token }}" \ 45 | -d '{ 46 | "event_type":"build ${{ matrix.device }}", 47 | "client_payload":{ 48 | "branch":"'$branch'", 49 | "device":"${{ matrix.device }}" 50 | } 51 | }' 52 | -------------------------------------------------------------------------------- /README-EN.md: -------------------------------------------------------------------------------- 1 | **English** | [中文](https://p3terx.com/archives/build-openwrt-with-github-actions.html) 2 | 3 | # Actions-OpenWrt 4 | 5 | [![LICENSE](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square&label=LICENSE)](https://github.com/P3TERX/Actions-OpenWrt/blob/master/LICENSE) 6 | ![GitHub Stars](https://img.shields.io/github/stars/P3TERX/Actions-OpenWrt.svg?style=flat-square&label=Stars&logo=github) 7 | ![GitHub Forks](https://img.shields.io/github/forks/P3TERX/Actions-OpenWrt.svg?style=flat-square&label=Forks&logo=github) 8 | 9 | A template for building OpenWrt with GitHub Actions 10 | 11 | ## Usage 12 | 13 | - Click the [Use this template](https://github.com/P3TERX/Actions-OpenWrt/generate) button to create a new repository. 14 | - Generate `.config` files using [Lean's OpenWrt](https://github.com/coolsnowwolf/lede) source code. ( You can change it through environment variables in the workflow file. ) 15 | - Push `.config` file to the GitHub repository. 16 | - Select `Build OpenWrt` on the Actions page. 17 | - Click the `Run workflow` button. 18 | - When the build is complete, click the `Artifacts` button in the upper right corner of the Actions page to download the binaries. 19 | 20 | ## Tips 21 | 22 | - It may take a long time to create a `.config` file and build the OpenWrt firmware. Thus, before create repository to build your own firmware, you may check out if others have already built it which meet your needs by simply [search `Actions-Openwrt` in GitHub](https://github.com/search?q=Actions-openwrt). 23 | - Add some meta info of your built firmware (such as firmware architecture and installed packages) to your repository introduction, this will save others' time. 24 | 25 | ## Credits 26 | 27 | - [Microsoft Azure](https://azure.microsoft.com) 28 | - [GitHub Actions](https://github.com/features/actions) 29 | - [OpenWrt](https://github.com/openwrt/openwrt) 30 | - [Lean's OpenWrt](https://github.com/coolsnowwolf/lede) 31 | - [tmate](https://github.com/tmate-io/tmate) 32 | - [mxschmitt/action-tmate](https://github.com/mxschmitt/action-tmate) 33 | - [csexton/debugger-action](https://github.com/csexton/debugger-action) 34 | - [Cowtransfer](https://cowtransfer.com) 35 | - [WeTransfer](https://wetransfer.com/) 36 | - [Mikubill/transfer](https://github.com/Mikubill/transfer) 37 | - [softprops/action-gh-release](https://github.com/softprops/action-gh-release) 38 | - [ActionsRML/delete-workflow-runs](https://github.com/ActionsRML/delete-workflow-runs) 39 | - [dev-drprasad/delete-older-releases](https://github.com/dev-drprasad/delete-older-releases) 40 | - [peter-evans/repository-dispatch](https://github.com/peter-evans/repository-dispatch) 41 | 42 | ## License 43 | 44 | [MIT](https://github.com/P3TERX/Actions-OpenWrt/blob/main/LICENSE) © [**P3TERX**](https://p3terx.com) 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 固件说明 2 | 3 | ### 支持的设备列表 4 | 5 | lede 仓库因为某些原因,会删掉某些 rockchip 设备的支持,这种情况请使用 骷髅头的版本(DHDAXCW) ,op 目前只有官方的 openwrt-21.02 分支看是能用的地步,immortalwrt(天灵) 的编译的话插件很多,最好 action 机器频率要 2700 以上 6 | 7 | | 设备(👇点击下载) | 支持的 源码-分支 列表 | 可脚本在线升级 | slim本地源 | 备注 | 8 | | ------ | ------------------ | ------- |---- | ---- | 9 | | [x86_64](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/x86_64) | [lede](https://github.com/coolsnowwolf/lede)、[op](https://github.com/openwrt/openwrt/tree/openwrt-21.02) | ✔ | ✔ | 开启了很多无线和板载驱动 | 10 | | [r2s](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/r2s) | [lede](https://github.com/coolsnowwolf/lede)、[op](https://github.com/openwrt/openwrt/tree/openwrt-21.02)、[DHDAXCW](https://github.com/DHDAXCW/lede-rockchip/tree/stable)、[immortalwrt](https://github.com/immortalwrt/immortalwrt/tree/openwrt-21.02) | ✔ | ✔ | 骷髅头 DHDAXCW 支持usb wifi 不死机 | 11 | | [r4s/r4se](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/r4s) | [lede](https://github.com/coolsnowwolf/lede)、[DHDAXCW](https://github.com/DHDAXCW/lede-rockchip/tree/stable)、[immortalwrt](https://github.com/immortalwrt/immortalwrt/tree/openwrt-18.06-k5.4) | ✔ | ✔ | op 的 21.02 target会变成r2s,喜欢op的用天灵的就行了,r4se用lede和骷髅头源码编译的,骷髅头的编译开启了gpu支持 | 12 | | [r5s](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/r5s) | [lede](https://github.com/coolsnowwolf/lede) | ✔ | ✔ | 刷机类似 doornet2,[教程](https://github.com/DHDAXCW/DoorNet2/blob/main/emmc.md) | 13 | | [h68k](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/h68k) | [lede](https://github.com/coolsnowwolf/lede)、[DHDAXCW/lede](https://github.com/DHDAXCW/lede) | ✔ | ✔ | lede的h68k兼容所有型号([需清emcc](https://github.com/coolsnowwolf/lede/issues/10286)),骷髅头的暂时只有h68k-a、h68k-c | 14 | | [RaspberryPi3](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/RaspberryPi3)| [immortalwrt](https://github.com/immortalwrt/immortalwrt/tree/openwrt-18.06-k5.4) | ✔ | ✔ | | 15 | | [RaspberryPi4](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/RaspberryPi4)| [immortalwrt](https://github.com/immortalwrt/immortalwrt/tree/openwrt-18.06-k5.4) | ✔ | ✔ | | 16 | | [r1s-h3](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/r1s-h3) | [lede](https://github.com/coolsnowwolf/lede) | ✔ | ✔ | 暂时没添加其他源码,sd卡可以,emcc刷入无法启动,不是我的锅 | 17 | | [r1s-h5](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/r1s-h5) | [immortalwrt](https://github.com/immortalwrt/immortalwrt/tree/openwrt-18.06-k5.4) | X | ✔ | 内存 500M,无法在线升级扩容 | 18 | | [doornet2](https://github.com/zhangguanzhang/Actions-OpenWrt/releases/tag/doornet2) | [lede](https://github.com/coolsnowwolf/lede)、[DHDAXCW](https://github.com/DHDAXCW/lede-rockchip/tree/doornet2) | ✔ | ✔ | 2022/09/01 lede 仓库删掉 doornet2支持,后续请使用骷髅头版本 | 19 | | N1 | [lede](https://github.com/coolsnowwolf/lede) | x | x | 暂时没空适配在线升级和slim | 20 | | k2p | [lede](https://github.com/coolsnowwolf/lede) | x | x | 暂时没空适配在线升级和slim | 21 | | sft1200 | [Siflower](https://github.com/Siflower/1806_SDK.git) | x | x | 暂时没空适配在线升级和slim | 22 | 23 | 24 | 推荐使用 `slim-squashfs` 本地源的版本,可以在自行 release 下载,或者点击上面的 `设备` 栏目下的设备跳转过去: 25 | 26 | ``` 27 | 下载慢可以下面的 gh 代理 28 | # https://github.cooluc.com/ 29 | ``` 30 | 31 | ### 在线升级 32 | 33 | 在线升级的要求:内存大于等于 1G,容量大于等于 3G,升级步骤为下: 34 | 35 | 1. tf 卡推荐使用软件 `balenaEtcher-Portable` ,压缩包里是 img 的话会自动解压刷入,`x86_64` 在导入成硬盘后,给硬盘扩容,例如添加最少 2G 容量,vmdk 格式必须添加为硬盘之前使用类似 vmware-diskmanager 之类的增加容量 36 | 2. 配置好 wan 口(接上级路由做 dhcp 客户端还是 ppoe 拨号都行)或者你的 x86_64 单网口,确保路由器能上网 37 | 3. 电脑(不要ttyd上升级) ssh 上去执行 `bash -x /update.sh` ,如果升级失败,请提 issue 贴日志,arm64 之类的升级死机的话可以试试升级过程物理降温。 38 | 4. 默认密码均为 `password` ,路由器 ip 你可以电脑接它的 lan 后看网关 IP 39 | 5. 初次升级的同时会扩容,**扩容完只有两个分区,剩余空间所有目录均可享用**,升级完后连上去,可以自行安装想要的软件源,例如下面 40 | 1. `opkg update` 41 | 2. `opkg install luci-i18n-dockerman-zh-cn` 有 `i18n-$pkg_name` 的就优先安装它,然后刷新 web 就能看到新服务了 42 | 6. 推荐使用 `squashfs` 格式固件,因为 `ext4` 格式的断电关机会有几率开机变成根分区只读,我的 r2s 和其他人都遇到过。如果你使用 `squashfs` 格式出现 `I/O Error` 请使用 `diskgenius` 之类扫描看看存在坏道否。 43 | 7. 可在线升级和多源码的都是支持切版本,例如当前是 lede-master 的 r2s 想切到 DHDAXCW 的 stable: 44 | 1. `SKIP_BACK=1 REPO=DHDAXCW IM_BRANCH=stable bash -x /update.sh` 45 | 2. 注意这样切换网卡配置会带过去后,可能web网络那里显示有问题,遇到后可以自行删掉网卡配置 `/etc/config/network` 重启,然后接 lan 后访问 web 参照 `/etc/config/network.bak` 配置之前的网络信息重新配置网络 46 | 47 | ## ci 涉及 48 | 49 | 1. 创建 img 文件,挂载使用 zstd 成目录,整个源码目录都会被 zstd 压缩 50 | 2. 然后使用 gh cli 登录和上传 split 文件,后续下载合并后解压再 mount img 成目录,就是缓存了之前的构建结果了 51 | 3. fork的话,想用我一样的 cache 和 slim 构建必须阿里云镜像仓库相关token,然后 gh cli 的token设置 52 | 4. 貌似一个 target 可以编译出多个,可能后续需要兼容下,例如 r4s 和 r4se 53 | 54 | ## 分隔 55 | 56 | 下面的内容是笔记,没整理,不要照抄执行 57 | 58 | ## 构建 59 | 60 | 机器最好 100G 以上 61 | 62 | ``` 63 | docker pull openwrtorg/sdk:x86_64-openwrt-21.02 64 | 65 | 66 | git clone https://github.com/coolsnowwolf/lede.git --depth 1 67 | cd lede 68 | 69 | docker run --name openwrt --rm -tid -v $PWD:/home/build/openwrt openwrtorg/sdk:x86_64-openwrt-21.02 70 | 71 | docker exec -ti openwrt bash 72 | 73 | echo "src-git small https://github.com/kenzok8/small" >> feeds.conf.default 74 | echo "src-git others https://github.com/kenzok8/openwrt-packages" >> feeds.conf.default 75 | 76 | 77 | 78 | ./scripts/feeds update -a 79 | 80 | ./scripts/feeds install -a 81 | 82 | rm -rf feeds/small/ipt2socks 83 | rm -rf feeds/small/pdnsd-alt 84 | rm -rf package/lean/kcptun 85 | rm -rf package/lean/trojan 86 | rm -rf feeds/small/v2ray-plugin 87 | 88 | make defconfig 89 | ./scripts/diffconfig.sh > seed.config 90 | ``` 91 | 92 | ``` 93 | # CONFIG_TARGET_IMAGES_GZIP is not set 94 | ``` 95 | 96 | ``` 97 | CONFIG_TARGET_IMAGES_GZIP=y 98 | 99 | CONFIG_TARGET_ROOTFS_PARTSIZE=2048 100 | ``` 101 | 102 | ``` 103 | Target System (x86) ---> 目标系统(x86) 104 | Subtarget (x86_64) ---> 子目标(x86_64) 105 | Target Profile (Generic) --->目标配置文件(通用) 106 | Target Images ---> 保存目标镜像的格式 107 | Global build settings ---> 全局构建设置 108 | Advanced configuration options (for developers) ---- 高级配置选项(适用于开发人员) 109 | Build the OpenWrt Image Builder 构建OpenWrt图像生成器 110 | Build the OpenWrt SDK构建OpenWrt SDK 111 | Package the OpenWrt-based Toolchain打包基于OpenWrt的工具链 112 | Image configuration ---> 图像配置 113 | Base system ---> 基本系统 114 | Administration ---> 管理 115 | Boot Loaders --->引导加载程序 116 | Development ---> 开发 117 | Extra packages ---> 额外包 118 | Firmware --->固件 119 | Fonts --->字体 120 | Kernel modules ---> 内核模块 121 | Languages --->语言 122 | Libraries ---> 库 123 | LuCI ---> LuCI 124 | Mail --->邮件 125 | Multimedia --->多媒体 126 | Network --->网络 127 | Sound ---> 声音 128 | Utilities --->实用程序 129 | Xorg --->Xorg 130 | ``` 131 | 132 | 文件格式区别 133 | 1:固件文件名中带有 ext4 字样的文件为搭载 ext4 文件系统固件,ext4 格式的固件更适合熟悉 Linux 系统的用户使用,在 Linux 下可以比较方便地调整 ext4 分区的大小; 134 | 135 | 2:固件文件名中带有 squashfs 字样的文件为搭载 squashfs 文件系统固件,而 squashfs 格式的固件适用于 “不折腾” 的用户,其优点是可以比较方便地进行系统还原,哪怕你一不小心玩坏固件,只要还能进入控制面板或 SSH,就可以很方便地进行 “系统还原操作”。 136 | 137 | 3:固件文件名中带有 sysupgrade 字样的文件为升级 OpenWrt 所用的固件,无需解压 gz 文件,可直接在 Luci 面板中升级。 138 | 139 | 4:rootfs的镜像,不带引导,可自行定义用 grub 或者 syslinux 来引导,存储区为 ext4。(小白不建议) 140 | 141 | 1:config.buildinfoOpenWrt --------------------------------------------------------------------------------编译配置文件 142 | 143 | 2:openwrt-rockchip-armv8-friendlyarm_nanopi-r2s-ext4-sysupgrade.img.gz--------------------------Ext4 格式固件 144 | 145 | 3:openwrt-rockchip-armv8-friendlyarm_nanopi-r2s-rootfs.tar.gz---------------------------------------RootFS 文件 146 | 147 | 4:openwrt-rockchip-armv8-friendlyarm_nanopi-r2s-squashfs-sysupgrade.img.gz---------------------Squashfs 格式固件 148 | 149 | 5:openwrt-rockchip-armv8-friendlyarm_nanopi-r2s.manifest------------------------------------------ 固件内已集成软件包列表 150 | 151 | 6:packages-server.zip-------------------------------------------------------------------------------------IPK 软件包归档 152 | 153 | 7:sha256sums--------------------------------------------------------------------------------------------------------固件完整性校验文件 154 | 155 | 8:Source code.zip-----------------------------------------------------------------------------------------源代码.zip 156 | 157 | 9:Source code(tar.gz)-------------------------------------------------------------------------------------源代码.tar.gz 158 | 159 | https://www.right.com.cn/forum/thread-3682029-1-1.html 160 | 161 | ## 参考 162 | - https://mlapp.cn/1009.html 163 | - https://www.v2rayssr.com/openwrtimg.html/comment-page-1 164 | - https://mianao.info/2020/05/05/%E7%BC%96%E8%AF%91%E6%9B%B4%E6%96%B0OpenWrt-PassWall%E5%92%8CSSR-plus%E6%8F%92%E4%BB%B6 165 | - [构建一个 op 的包的时候 Makefile 如何编写和讲解](https://blog.51cto.com/u_15346415/3694615) 166 | - [Makefile 框架分析](https://www.cnblogs.com/happygirl-zjj/p/6008239.html) 167 | 168 | ## 缓存和避免包的重复编译 169 | 170 | 缓存见 cache.sh 。主要是包的重复编译如何避免,先看单个包 `./package/utils/lua` 的编译步骤: 171 | 172 | 1. 在 make 时,make 读取到 `package/utils/lua/Makefile` 文件内容,包含版本和下载地址。 173 | 2. 如果 git 或 svn 源,那么就会在 tmp/dl/ 目录下将源代码 clone 下来。然后,将 clone 下来的源码删除 .git 或 .svn 目录删除,然后压缩成 `lua-x.x.x.tar.gz` 文件,并复制到 dl/ 目录下。 174 | 3. 在编译前段,将 dl/ 目录下的 lua-x.x.x.tar.gz 文件解压到 `build_dir/target-/lua-x.x.x/` 目录下。 175 | 4. 进入 `build_dir/target-/lua-x.x.x/` 执行 `./configure`,`make`,`make install`。 176 | 5. make install 会将生成的二进制文件安装到 `build_dir/target-/lua-x.x.x/ipkg-/` 目录下。 177 | 6. 最后将 `build_dir/target-/lua-x.x.x/ipkg-/` 打包成 `lua-x.x.x-1_.ipk`,并复制到 `bin//packages/base/` 。 178 | 179 | 可以大概看看 https://github.com/openwrt/openwrt/blob/master/include/package-ipkg.mk ,实际上 `build_dir/target-/lua-x.x.x/` 目录下有一些隐藏文件,`.built`、`.built_check` 可能是再次编译的判断文件 180 | 181 | ## 一些技巧 182 | 183 | dnsmasq 取消 `/etc/resolv.conf` 里的 `nameserver ::1` 184 | 185 | ``` 186 | cat /etc/init.d/dnsmasq 187 | [ -e /proc/sys/net/ipv6 ] && DNS_SERVERS="$DNS_SERVERS ::1" 188 | 189 | /etc/init.d/dnsmasq reload 190 | ``` 191 | 192 | https://www.youtube.com/watch?v=35ImdukpmyY 193 | 194 | 195 | https://openwrt.org/zh/docs/guide-user/additional-software/imagebuilder 196 | 197 | 198 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2019-2020 P3TERX 3 | # 4 | # This is free software, licensed under the MIT License. 5 | # See /LICENSE for more information. 6 | # 7 | # https://github.com/P3TERX/Actions-OpenWrt 8 | # Description: Build OpenWrt using GitHub Actions 9 | # 10 | 11 | name: Build OpenWrt 12 | 13 | on: 14 | repository_dispatch: 15 | workflow_dispatch: 16 | inputs: 17 | ssh: 18 | description: 'SSH connection to Actions' 19 | required: false 20 | default: 'false' 21 | target: 22 | description: 'build/${target} to build' 23 | required: false 24 | default: 'r2s' #'x86_64' 25 | envOverride: 26 | description: 'key=value,key2=value2' 27 | required: false 28 | default: '' 29 | repo_json: 30 | description: 'json raw string about repo to use' 31 | required: false 32 | default: '' 33 | config: 34 | description: 'config file to build' 35 | required: false 36 | default: 'config.buildinfo' 37 | os: 38 | description: 'os to use, or self-hosted' 39 | required: false 40 | default: 'ubuntu-20.04' 41 | branch: 42 | description: 'used for repository_dispatch run' 43 | required: false 44 | default: '' 45 | 46 | env: 47 | FEEDS_CONF: feeds.conf.default 48 | DIY_P1_SH: diy-part1.sh 49 | DIY_P2_SH: diy-part2.sh 50 | DIY_AFTER: diy-after.sh 51 | UPLOAD_BIN_DIR: false 52 | UPLOAD_FIRMWARE: true 53 | UPLOAD_COWTRANSFER: false 54 | UPLOAD_WETRANSFER: false 55 | UPLOAD_RELEASE: false 56 | TZ: Asia/Shanghai 57 | # DOCKER_HUB_PASS: ${{ secrets.DOCKER_PASS }} 58 | # ALIUNCS_PASS: ${{ secrets.DOCKER_PASS }} 59 | NOT_PUSH: ${{ secrets.NOT_PUSH }} 60 | envOverride: ${{ github.event.inputs.envOverride }} 61 | 62 | jobs: 63 | set_matrix: 64 | runs-on: ubuntu-latest 65 | # runs-on: ${{ github.event.inputs.os }} || {{ github.event.client_payload }} 66 | outputs: 67 | build_repo: ${{ steps.set_matrix.outputs.matrix }} 68 | real_target: ${{ steps.set_matrix.outputs.target }} 69 | inputs_json: ${{ steps.set_matrix.outputs.input }} 70 | name: "set matrix for: ${{ github.event.inputs.target }}" 71 | 72 | steps: 73 | - name: Checkout 74 | uses: actions/checkout@main 75 | 76 | - name: prinf info 77 | id: set_matrix 78 | run: | 79 | [ -n "${{ github.event.inputs.branch }}" ] && real_branch=${{ github.event.inputs.branch }} 80 | [ -n "${{ github.event.client_payload.branch }}" ] && real_branch=${{ github.event.client_payload.branch }} 81 | [ -z "$real_branch" ] && real_branch=${GITHUB_REF##*/} 82 | echo "real_branch: $real_branch" 83 | git fetch && git reset --hard origin/${real_branch} && git clean -df 84 | 85 | echo '${{ toJson(github) }}' > /tmp/github 86 | cat /tmp/github 87 | pwd # /home/runner/work/Actions-OpenWrt/Actions-OpenWrt 88 | ls -al 89 | # set $1 90 | set -- set 91 | source build/common/scripts/start_set_matrix.sh 92 | 93 | 94 | - name: prinf set_matrix 95 | run: | 96 | echo '${{ steps.set_matrix.outputs.matrix }}' 97 | 98 | build: 99 | needs: set_matrix 100 | runs-on: ${{ fromJson(needs.set_matrix.outputs.inputs_json).os }} # ${{ needs.set_matrix.outputs.os }} 101 | outputs: 102 | imageBuilder: ${{ steps.organize.outputs.imageBuilder }} 103 | build_target: ${{ steps.organize.outputs.build_target }} 104 | name: "${{matrix.target}}:${{matrix.repo.name}}-${{matrix.repo.branch}}" 105 | strategy: 106 | fail-fast: false 107 | matrix: 108 | target: 109 | #- "${{ github.event.inputs.target }}" 110 | - ${{ fromJson(needs.set_matrix.outputs.inputs_json).target }} #"${{ needs.set_matrix.outputs.real_target }}" 111 | repo: ${{ fromJson(needs.set_matrix.outputs.build_repo) }} 112 | 113 | steps: 114 | - name: Checkout 115 | uses: actions/checkout@main 116 | 117 | - name: prinf machine info and matrix info 118 | run: | 119 | real_branch=${GITHUB_REF##*/} 120 | if [ -n "${{ github.event.inputs.branch }}" ];then 121 | real_branch=${{ github.event.inputs.branch }} 122 | fi 123 | [ -n "${{ github.event.client_payload.branch }}" ] && real_branch=${{ github.event.client_payload.branch }} 124 | git fetch && git reset --hard origin/${real_branch} && git clean -df 125 | echo "real_branch=${real_branch}" >> $GITHUB_ENV 126 | 127 | echo '${{ needs.set_matrix.outputs.inputs_json }}' > /tmp/github.json 128 | cat /tmp/github.json 129 | source build/common/scripts/start_set_matrix.sh 130 | 131 | 132 | uname -a 133 | cat /etc/os-release 134 | df -h 135 | lscpu 136 | free -h 137 | echo 'target: ${{ matrix.target }} ${{ toJSON(matrix.repo) }}' 138 | # 移动 $target ,后续步骤不记得不需要用 build/${{ github.event.inputs.target }} 139 | cp -a build/${{ matrix.target }}/* ${GITHUB_WORKSPACE}/ 140 | cp -a ${GITHUB_WORKSPACE}/build/common ${GITHUB_WORKSPACE}/ 141 | 142 | echo "build_target=${{ matrix.target }}" >> $GITHUB_ENV 143 | 144 | if [ "${os}" != 'self-hosted' ];then 145 | if [ "${real_branch}" = 'test' ] && [ "$(LANG=en_US.UTF-8 lscpu | awk '$1=="CPU"&&$2=="MHz:"{print int($3)}')" -le 2500 ];then 146 | hour_num=$(TZ=Asia/Shanghai date '+%H') 147 | # 白天频率太小不执行,晚上可以定时任务执行 148 | if [ "${{ github.repository_owner }}" = zhangguanzhang ] && [ $hour_num -ge 9 ];then 149 | # 多个 matrix repo 编译无视频率 150 | if [ -z "${repo_json}" ] && ! grep -Pq '^\s*[^#]+?\},\{' ${GITHUB_WORKSPACE}/set_matrix.sh;then 151 | echo "cpu 频率太小,不执行" 152 | #exit 233 153 | fi 154 | fi 155 | fi 156 | fi 157 | 158 | # - name: install docker 159 | # uses: docker-practice/actions-setup-docker@master 160 | 161 | - name: Login to Docker Hub 162 | uses: docker/login-action@v2 163 | env: 164 | DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASS }} 165 | if: env.DOCKER_PASS != '' 166 | with: 167 | username: ${{ github.repository_owner }} 168 | password: ${{ secrets.DOCKER_HUB_PASS }} 169 | 170 | # - name: Login to registry.aliyuncs.com 171 | # uses: aliyun/acr-login@v1 172 | # env: 173 | # DOCKER_PASS: ${{ secrets.ALIUNCS_PASS }} 174 | # if: env.DOCKER_PASS != '' 175 | # with: 176 | # login-server: https://registry.aliyuncs.com 177 | # username: "${{ github.repository_owner }}@qq.com" 178 | # password: "${{ secrets.ALIUNCS_PASS }}" 179 | 180 | - name: Initialization environment 181 | env: 182 | DEBIAN_FRONTEND: noninteractive 183 | run: | 184 | sudo swapoff -a 185 | sudo rm -f /mnt/swapfile 186 | sudo mkdir -p /workdir 187 | sudo chown $USER:$GROUPS /workdir 188 | git config --global user.email "action@github.com" && git config --global user.name "GitHub Action" 189 | 190 | # $target/init_runner.sh 设置 runner 的基础设置 191 | if [ -f "init_runner.sh" ];then 192 | bash init_runner.sh 193 | else 194 | # curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 195 | # echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | \ 196 | # sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null 197 | # 包管理安装可能会失败 198 | if [ "${os}" != 'self-hosted' ];then 199 | sudo rm -rf /etc/apt/sources.list.d/* /usr/share/dotnet /usr/local/lib/android /opt/ghc 200 | fi 201 | sudo -E apt-get -qq update 202 | #sudo apt-cache search lib32gcc1 203 | sudo -E apt-get -qq install $(curl -fsSL git.io/depends-ubuntu-2004 | sed -r 's/lib32gcc1\S*//') \ 204 | zstd upx jq pv ccache $(sudo apt-cache search lib32gcc1 | awk 'NR==1{if($1=="lib32gcc1"){print $1}else{print "lib32gcc-s1"}}') skopeo parallel 205 | sudo -E apt-get -qq autoremove --purge 206 | sudo -E apt-get -qq clean 207 | sudo timedatectl set-timezone "$TZ" 208 | 209 | # install github cli tool 210 | # gh 的 cli 用于构建缓存存储,这里加 env 判断防止 fork 的人不知道怎么设置而构建失败 211 | if [ -n "${{ secrets.gh_token }}" ];then 212 | wget -q $(curl -s https://api.github.com/repos/cli/cli/releases/latest | jq -r '.assets[] | select(.name|match("linux_amd64.tar.gz$")) | .browser_download_url') 213 | tar zxf gh_*_linux_amd64.tar.gz 214 | find gh_* -type f -name gh -exec mv {} /usr/local/bin/ \; 215 | rm -rf gh_*linux* 216 | sudo chmod a+x /usr/local/bin/gh 217 | gh --version 218 | echo ${{ secrets.gh_token }} | gh auth login --with-token 219 | fi 220 | fi 221 | 222 | { 223 | git clone https://github.com/openwrt-dev/po2lmo.git 224 | pushd po2lmo 225 | make && sudo make install 226 | popd 227 | rm -rf po2lmo 228 | }& 229 | 230 | docker rmi `docker images -q` & 231 | # 名字和上方保持一致格式 232 | echo "JOB_NAME=${{matrix.target}}:${{matrix.repo.name}}-${{matrix.repo.branch}}" >> $GITHUB_ENV 233 | # 设置一些 condition 给后续步骤作为判断条件或者执行的值 234 | bash common/env.sh 235 | # name-branch-target 236 | echo "cache_name=$( echo ${{ matrix.repo.name }}-${{ matrix.repo.branch }}-${{ matrix.target }} | awk -F/ '{print $NF}' )" >> $GITHUB_ENV 237 | 238 | echo "ACTION_NUM=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV 239 | 240 | - name: Clone source code 241 | working-directory: /workdir 242 | run: | 243 | set -x 244 | df -hT $PWD 245 | if [ "$UseCache" = true -a -n "${{ secrets.gh_token }}" ];then 246 | echo 'repository_owner=${{ github.repository_owner }}' >> $GITHUB_ENV 247 | bash -x ${GITHUB_WORKSPACE}/common/cache.sh download 248 | fi 249 | if [ ! -f "${GITHUB_WORKSPACE}/${cache_name}.img" ];then 250 | truncate -s 33g ${GITHUB_WORKSPACE}/${cache_name}.img && mkfs.btrfs -M ${GITHUB_WORKSPACE}/${cache_name}.img 251 | echo "CACHE=false" >> $GITHUB_ENV 252 | else 253 | echo "CACHE=true" >> $GITHUB_ENV 254 | fi 255 | LOOP_DEVICE=$(losetup -f) && echo "LOOP_DEVICE=$LOOP_DEVICE" >> $GITHUB_ENV 256 | sudo losetup -P --direct-io $LOOP_DEVICE ${GITHUB_WORKSPACE}/${cache_name}.img 257 | 258 | # https://forum.openwrt.org/t/using-precompiled-toolchain/87446/6 259 | # 直接缓存所有目录得了 260 | #mkdir -p cache/{build_dir,staging_dir,tmp} openwrt/{build_dir,staging_dir,tmp} 261 | 262 | mkdir openwrt && sudo mount -o nossd,compress=zstd $LOOP_DEVICE openwrt 263 | # 有些特殊设备单独自己维护缓存和没缓存的目录准备工作 264 | if [ -f "${GITHUB_WORKSPACE}/clone.sh" ];then 265 | bash ${GITHUB_WORKSPACE}/clone.sh 266 | else 267 | if [ -d 'openwrt/.git' ]; then 268 | cd openwrt 269 | rm -f zerospace 270 | git config --local user.email "action@github.com" && git config --local user.name "GitHub Action" 271 | git fetch && git reset --hard origin/${{ matrix.repo.branch }} && git clean -df 272 | else 273 | sudo chown $USER:$(id -gn) openwrt && git clone -b ${{ matrix.repo.branch }} --single-branch ${{ matrix.repo.addr }} openwrt 274 | fi 275 | ln -sf /workdir/openwrt $GITHUB_WORKSPACE/openwrt 276 | echo "BaseDir=/workdir/openwrt" >> $GITHUB_ENV 277 | fi 278 | if [ "${os}" == 'self-hosted' ];then 279 | sudo chown -R $USER:$(id -gn) /workdir/openwrt 280 | fi 281 | cd ${BaseDir} 282 | readlink -f $GITHUB_WORKSPACE/openwrt 283 | ls -la . $GITHUB_WORKSPACE/ $GITHUB_WORKSPACE/common $GITHUB_WORKSPACE/config $GITHUB_WORKSPACE/openwrt/ 284 | 285 | echo "repo_name=${{ matrix.repo.name }}" >> $GITHUB_ENV 286 | echo "repo_branch=${{ matrix.repo.branch }}" >> $GITHUB_ENV 287 | 288 | - name: Load custom feeds 289 | run: | 290 | [ -e $FEEDS_CONF ] && mv $FEEDS_CONF openwrt/feeds.conf.default 291 | if [ -f "$DIY_P1_SH" ];then 292 | chmod +x $DIY_P1_SH 293 | cd openwrt 294 | echo "Start Running: $DIY_P1_SH" 295 | $GITHUB_WORKSPACE/$DIY_P1_SH 296 | fi 297 | 298 | - name: Update feeds 299 | if: env.UdateFeeds == 'true' 300 | run: | 301 | cd openwrt 302 | set -x 303 | awk '$1!~"#"{print $2}' feeds.conf.default | while read dir;do 304 | if [ -d feeds/${dir}/.git ];then 305 | pushd feeds/${dir} 306 | [ -n "$(git diff --name-only)" ] && git reset --hard HEAD 307 | git clean -df 308 | git restore . 309 | git pull --rebase 310 | popd 311 | fi 312 | done 313 | ./scripts/feeds update -a 314 | 315 | 316 | - name: Install feeds 317 | if: env.InstallFeeds == 'true' 318 | run: cd openwrt && ./scripts/feeds install -a 319 | 320 | - name: Load custom configuration 321 | id: load 322 | run: | 323 | 324 | source $GITHUB_WORKSPACE/build/common/scripts/custom.sh 325 | 326 | set -x 327 | if [ -n "${{ secrets.gh_token }}" ] && [ "$CACHE" = false ] && [ "$USED_CONFIG_IB" = true ];then 328 | echo "::set-output name=status::true" 329 | fi 330 | 331 | - name: Upload buildInfo 332 | uses: actions/upload-artifact@main 333 | if: '!cancelled()' 334 | with: 335 | name: buildInfo${{ env.DEVICE_NAME }}-${{ env.cache_name }}-${{ env.ACTION_NUM }} 336 | # https://github.com/actions/upload-artifact/issues/92 337 | path: | 338 | ${{ env.BaseDir }}/.config 339 | ${{ env.BaseDir }}/*.buildinfo 340 | 341 | # 这个name 用于后续判断,里面的 run 就随意写了 342 | - name: gh-rerun-condition 343 | continue-on-error: true 344 | if: steps.load.outputs.status == 'true' 345 | run: | 346 | echo $JOB_NAME 347 | timeout 5 gh -R ${GITHUB_REPOSITORY} run watch ${{ github.run_id }} || true 348 | 349 | - name: cat .config part1 350 | run: | 351 | cd openwrt 352 | cat .config 353 | 354 | - name: SSH connection to Actions 355 | uses: P3TERX/ssh2actions@v1.0.0 356 | if: (failure() && github.event.inputs.ssh == 'true' && github.event.inputs.ssh != 'false') || contains(github.event.action, 'ssh') 357 | env: 358 | TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} 359 | TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} 360 | 361 | - name: Download package 362 | id: package 363 | run: | 364 | cd openwrt 365 | if [ "$MakeDownload" == true ];then 366 | if [ -f dl/time ];then 367 | # last_time=$(cat dl/time) 368 | # # echo 3*24*60*60 | bc # 超过上一次三天就清理一次 369 | # if [ $(( `date +%s` - $last_time )) -ge 259200 ] && [ ];then 370 | # echo "dl 缓存清理" 371 | # rm -rf dl tmp 372 | # else 373 | echo "dl 缓存命中" 374 | # fi 375 | # else 376 | # mkdir -p dl 377 | # date +%s > dl/time 378 | fi 379 | make download -j8 380 | # 此处 -type f 限制的话会影响 golang 的包编译貌似 381 | # github 应该不存在拉取包失败,所以非 github 才需要这样 382 | if [ -z "${GITHUB_REPOSITORY}" ];then 383 | find dl -size -1024c -exec ls -l {} \; 384 | find dl -size -1024c -exec rm -f {} \; 385 | fi 386 | fi 387 | ls -al ${BaseDir} 388 | 389 | - name: cat .config before compile 390 | run: | 391 | cd openwrt 392 | # 看哪些被依赖开启的 luci-app-xxx=y,由于 common 开启的就不管,不在列表的话就需要看看是哪些依赖 393 | grep -P '^CONFIG_PACKAGE_luci-app-[^A-Z]*=y' .config 394 | echo '-----👇------' 395 | cat .config 396 | 397 | - name: Compile the firmware 398 | id: compile 399 | run: | 400 | ulimit -SHn 65000 401 | cd openwrt 402 | 403 | # 注入几个变量,给升级脚本做判断使用 404 | release_file=$( find package/base-files -type f -name openwrt_release ) 405 | echo "release_file path: $release_file" 406 | # ${{matrix.target}}: ${{matrix.repo.name}}-${{matrix.repo.branch}} 407 | echo "MATRIX_TARGET='${{matrix.target}}'" >> $release_file 408 | echo "MATRIX_REPO_NAME='${{matrix.repo.name}}'" >> $release_file 409 | echo "MATRIX_REPO_BRANCH='${{matrix.repo.branch}}'" >> $release_file 410 | # multi target 的时候写入信息,给升级脚本做适配 411 | if grep -Pq '^\s*CONFIG_TARGET_MULTI_PROFILE=y' .config;then 412 | # firmware_wildcard 会在 diy2.sh 里改写 413 | echo "MATRIX_TARGET_LIST='${firmware_wildcard}'" >> $release_file 414 | # 通过 job 传递有问题,通过文件传递吧 415 | echo "multi_target=${firmware_wildcard}" >> imageBuilderEnv.buildinfo 416 | fi 417 | 418 | echo -e "$(nproc) thread compile" 419 | if [ -n "${{ secrets.gh_token }}" -a "${AutoBuildTimeOut}" == true ] ;then 420 | createdAt=$(gh -R ${GITHUB_REPOSITORY} run list --json databaseId,createdAt --jq ".[]|select(.databaseId==${{ github.run_id }})|.createdAt") 421 | echo "createdAt=$createdAt" >> $GITHUB_ENV 422 | 423 | set -x 424 | mkdir -p env/ 425 | touch env/toolchain.hash 426 | CURRENT_HASH=$(git log --pretty=tformat:"%H" -n1 tools toolchain) 427 | CACHE_HASH=$(cat env/toolchain.hash) 428 | # 这里用 git commit 判断是否需要编译,否则 clone upx ucl 的时候会被判定认为 tools 更新了 429 | # 然后每次更新就浪费大概 1 个小时,拆解 make 步骤参考: 430 | # https://github.com/SuLingGG/OpenWrt-Rpi/blob/31c574d043d65328d6c8d7fb9cab388941336445/.github/workflows/x86-64.yml#L114 431 | # https://github.com/DHDAXCW/NanoPi-R4S-R4SE/blob/main/.github/workflows/NanoPi-R4S-Plus.yml 432 | # 推荐看骷髅头的,suling的写得太散了 433 | if [ -z "$CACHE_HASH" ] || [ "$CURRENT_HASH" != "$CACHE_HASH" ]; then 434 | echo 'star compile tools' 435 | time make tools/compile -j$[`nproc`+1] || make tools/compile -j1 V=s 436 | # tools 编译的时候和 toolchain 貌似会一起编译 437 | time make toolchain/compile -j$[`nproc`+1] || make toolchain/compile -j1 V=s 438 | echo $CURRENT_HASH > env/toolchain.hash 439 | fi 440 | 441 | make buildinfo 442 | make diffconfig buildversion feedsversion 443 | time make target/compile -j$[`nproc`+1] IGNORE_ERRORS="m n" BUILD_LOG=1 || \ 444 | yes n | make target/compile -j1 V=s IGNORE_ERRORS=1 445 | 446 | usedSec=$(( `date +%s` - `date -d "$createdAt" +%s` )) 447 | # 6小时超时,减去上传 cache 预留的 22 分钟后的时间作为 timeout 时间 448 | 449 | reserved_time=$( bash ${GITHUB_WORKSPACE}/common/cache.sh get_reserved_time) 450 | # 每种缓存方式时间预留不一样 451 | timeoutSec=$(( 6*60*60 - ${reserved_time}*60 - $usedSec )) 452 | time timeout $timeoutSec make package/compile -j$[`nproc`+1] IGNORE_ERRORS=1 |& tee -a /tmp/build.log 453 | if ! grep -qw Terminated /tmp/build.log;then 454 | usedSec=$(( `date +%s` - `date -d "$createdAt" +%s` )) 455 | if grep -qw 're-run make' /tmp/build.log;then 456 | # 小于 5 小时构建完,此刻单独构建失败的 457 | if [ $usedSec -lt $((47*60*6)) ];then 458 | timeoutSec=$(( 6*60*60 - ${reserved_time}*60 - $usedSec )) 459 | echo 'failed: try to V=s' 460 | time timeout $timeoutSec make package/compile -j1 V=s IGNORE_ERRORS=1 || make package/index 461 | fi 462 | else 463 | time make package/install || make package/install -j1 V=s 464 | timeoutSec=$(( 6*60*60 - ${reserved_time}*60 - $usedSec )) 465 | if [ $timeoutSec -gt 0 ];then 466 | command="timeout $timeoutSec" 467 | fi 468 | time make package/index || true 469 | time $command make target/install || make target/install -j1 V=s 470 | make json_overview_image_info 471 | make checksum 472 | fi 473 | else 474 | time make package/index || true 475 | fi 476 | set +x 477 | else 478 | make -j$[`nproc`+1] || make -j1 || make -j1 V=s 479 | fi 480 | echo "FILE_DATE=_$(date +"%Y%m%d%H%M")" >> $GITHUB_ENV 481 | echo "=======================" 482 | echo "Space usage:" 483 | echo "=======================" 484 | df -h 485 | echo "=======================" 486 | du -h --max-depth=1 ./ --exclude=build_dir --exclude=bin 487 | du -h --max-depth=1 ./build_dir 488 | du -h --max-depth=1 ./bin 489 | 490 | echo "DEVICE_NAME=${{ matrix.target }}" >> $GITHUB_ENV 491 | 492 | 493 | - name: retry with V=s in failed packages 494 | if: (!cancelled()) 495 | run: | 496 | cd openwrt 497 | # 编译时间很早完成的话,make -v 看下 ERROR: package/feeds/routing/cjdns failed to build. 的编译错误信息 498 | if [ -n "${{ secrets.gh_token }}" ];then 499 | usedSec=$(( `date +%s` - `date -d "$createdAt" +%s` )) 500 | # 小于 5 小时构建完,此刻单独构建失败的 501 | if [ $usedSec -lt $((4*60*60)) ];then 502 | grep -Po 'ERROR:\s+\K\S+' /tmp/build.log || true 503 | echo '-------------分割线-----------' 504 | for pkg in `grep -Po 'ERROR:\s+\K\S+' /tmp/build.log`;do 505 | echo "开始单独尝试 make $pkg/compile V=s 编译查看详细信息" 506 | make $pkg/compile V=s || true 507 | done 508 | fi 509 | fi 510 | 511 | - name: Check space usage 512 | if: (!cancelled()) 513 | run: | 514 | df -hT 515 | df -i 516 | ls -la openwrt/ 517 | #ls -lh openwrt/bin/targets/*/* # 有时候是目录 openwrt/bin/targets/* 518 | # 所以用下面定位目录 519 | ls -lh $(dirname $(find openwrt/bin/targets/ -type d -name packages )) 520 | if [ -f diy-after-compile.sh ];then 521 | bash diy-after-compile.sh 522 | fi 523 | 524 | - name: Check cache list 525 | if: (!cancelled()) 526 | run: | 527 | cd openwrt/ 528 | if [ -d dl/ ];then 529 | ls -ahl dl/ 530 | fi 531 | ls -ahl build_dir/target-*/ staging_dir/target-* \ 532 | staging_dir/packages || true 533 | 534 | - name: Upload bin directory 535 | uses: actions/upload-artifact@main 536 | if: steps.compile.outputs.status == 'success' && env.UPLOAD_BIN_DIR == 'true' 537 | with: 538 | name: OpenWrt_bin_${{ env.DEVICE_NAME }}${{ env.FILE_DATE }} 539 | path: openwrt/bin 540 | 541 | - name: Organize files 542 | id: organize 543 | if: env.UPLOAD_FIRMWARE == 'true' && !cancelled() 544 | run: | 545 | 546 | sha256_path=$(find openwrt/bin/targets/ -type f -name sha256sums ) 547 | if [ -n "$sha256_path" ];then 548 | cd $(dirname $sha256_path) 549 | pwd 550 | rm -rf packages 551 | echo "FIRMWARE=$PWD" >> $GITHUB_ENV 552 | # 有固件生成,则上传 553 | if [ `find -type f -size +5M | grep -Ev 'openwrt-imagebuilder' |wc -l` -ne 0 ];then 554 | echo "success build" 555 | # 多个matrix 同时构建,不上传目录 556 | if ! grep -Pq '^\s*[^#]+?\},\{' ${GITHUB_WORKSPACE}/set_matrix.sh;then 557 | echo "::set-output name=status::success" 558 | fi 559 | fi 560 | 561 | # 下面 outputs 是后面上传 imageBuidler 的判断条件和名字 562 | if ls *-imagebuilder-* &>/dev/null;then 563 | # # 避免以后其他的 repo 构建的默认就带 imagebuilder,例如 sft1200。上传 imageBuilder 但是不给后续的 slim/full 执行 564 | echo "::set-output name=uploadImageBuilder::true" 565 | if [ "${CACHE}" = true ] && [ "$USED_CONFIG_IB" == true ];then 566 | echo "::set-output name=imageBuilder::openwrt-imagebuilder-${{ env.DEVICE_NAME }}-${{ matrix.repo.name }}-${{ matrix.repo.branch }}" 567 | fi 568 | else 569 | echo "no_imageBuilder=true" >> $GITHUB_ENV 570 | fi 571 | echo "::set-output name=build_target::${{ matrix.target }}" 572 | fi 573 | 574 | - name: Do something after Compile 575 | if: steps.organize.outputs.status == 'success' && !cancelled() 576 | run: | 577 | cd openwrt 578 | # 没 imageBuilder下也就是不做slim的设备此刻执行 after 579 | if [ -f "$GITHUB_WORKSPACE/$DIY_AFTER" ] && [ "$no_imageBuilder" = true ] ;then 580 | export real_branch 581 | bash $GITHUB_WORKSPACE/$DIY_AFTER 582 | fi 583 | 584 | - name: Upload firmware directory 585 | uses: actions/upload-artifact@main 586 | if: steps.organize.outputs.status == 'success' && !cancelled() 587 | with: # 上传固件 588 | name: OpenWrt_firmware_${{ env.DEVICE_NAME }}${{ env.FILE_DATE }}-${{ matrix.repo.name }}-${{ matrix.repo.branch }} 589 | path: | 590 | ${{ env.FIRMWARE }} 591 | !${{ env.FIRMWARE }}/openwrt-imagebuilder* 592 | 593 | - name: Upload imagebuilder tar.xz 594 | uses: actions/upload-artifact@main 595 | if: steps.organize.outputs.uploadImageBuilder && !cancelled() 596 | with: # 上传 imageBuilder 597 | name: openwrt-imagebuilder-${{ env.DEVICE_NAME }}-${{ matrix.repo.name }}-${{ matrix.repo.branch }} 598 | path: ${{ env.FIRMWARE }}/*-imagebuilder* 599 | 600 | - name: Upload firmware to cowtransfer 601 | id: cowtransfer 602 | if: steps.organize.outputs.status == 'success' && env.UPLOAD_COWTRANSFER == 'true' && !cancelled() 603 | run: | 604 | curl -fsSL git.io/file-transfer | sh 605 | ./transfer cow --block 2621440 -s -p 64 --no-progress ${FIRMWARE} 2>&1 | tee cowtransfer.log 606 | echo "::warning file=cowtransfer.com::$(cat cowtransfer.log | grep https)" 607 | echo "::set-output name=url::$(cat cowtransfer.log | grep https | cut -f3 -d" ")" 608 | 609 | - name: Upload firmware to WeTransfer 610 | id: wetransfer 611 | if: steps.organize.outputs.status == 'success' && env.UPLOAD_WETRANSFER == 'true' && !cancelled() 612 | run: | 613 | curl -fsSL git.io/file-transfer | sh 614 | ./transfer wet -s -p 16 --no-progress ${FIRMWARE} 2>&1 | tee wetransfer.log 615 | echo "::warning file=wetransfer.com::$(cat wetransfer.log | grep https)" 616 | echo "::set-output name=url::$(cat wetransfer.log | grep https | cut -f3 -d" ")" 617 | 618 | - name: Generate release tag 619 | id: tag 620 | if: env.UPLOAD_RELEASE == 'true' && !cancelled() 621 | run: | 622 | echo "::set-output name=release_tag::$(date +"%Y.%m.%d-%H%M")" 623 | touch release.txt 624 | [ $UPLOAD_COWTRANSFER = true ] && echo "🔗 [Cowtransfer](${{ steps.cowtransfer.outputs.url }})" >> release.txt 625 | [ $UPLOAD_WETRANSFER = true ] && echo "🔗 [WeTransfer](${{ steps.wetransfer.outputs.url }})" >> release.txt 626 | echo "::set-output name=status::success" 627 | 628 | - name: Upload firmware to release 629 | uses: softprops/action-gh-release@v1 630 | if: steps.tag.outputs.status == 'success' && !cancelled() 631 | env: 632 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 633 | with: 634 | tag_name: ${{ steps.tag.outputs.release_tag }} 635 | body_path: release.txt 636 | files: ${{ env.FIRMWARE }}/* 637 | 638 | - name: Clean space for upload cache 639 | id: up_cache_before 640 | if: "!cancelled() && env.ClearPkg == 'true'" 641 | continue-on-error: true 642 | run: | 643 | sync 644 | sha256_path=$(find openwrt/bin/targets/ -type f -name sha256sums ) 645 | if [ -n "$sha256_path" ];then 646 | pushd $(dirname $sha256_path) 647 | if ls *-imagebuilder-* &>/dev/null;then 648 | # 有 imagebuilder下,清理下,防止此步上传超时 649 | rm -rf openwrt-* 650 | fi 651 | popd 652 | fi 653 | 654 | nohup sh -c ' 655 | echo "Listing 100 largest packages" 656 | sudo dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | tail -n 100 657 | df -h 658 | echo "Removing large packages" 659 | sudo apt-get remove -y '^ghc-8.*' || true 660 | sudo apt-get remove -y '^dotnet-.*' || true 661 | sudo apt-get remove -y '^llvm-.*' || true 662 | sudo apt-get remove -y 'php.*' || true 663 | sudo apt-get remove -y azure-cli google-cloud-sdk hhvm google-chrome-stable firefox powershell mono-devel || true 664 | sudo apt-get autoremove -y || true 665 | sudo apt-get clean || true 666 | df -h 667 | df -i 668 | ' & 669 | 670 | - name: Upload cache 671 | id: up_cache 672 | if: '!cancelled()' 673 | env: 674 | repo_pass: ${{ secrets.DOCKER_HUB_PASS }} 675 | gh_package_token: ${{ secrets.gh_package_token }} 676 | continue-on-error: true 677 | run: | 678 | 679 | if [ "${UseCache}" == true -a -n "${{ secrets.gh_token }}" ];then 680 | set -x 681 | # tmp 貌似是必须删除的 682 | rm -rf openwrt/{bin,tmp,files} 683 | 684 | if [ -z "$no_imageBuilder" ];then 685 | pushd openwrt 686 | df -h 687 | make V=s clean 688 | df -h 689 | popd 690 | fi 691 | 692 | bash ${GITHUB_WORKSPACE}/common/cache.sh clean 693 | 694 | # https://unix.stackexchange.com/questions/18048/list-only-bind-mounts 695 | # for path in `sudo findmnt --kernel -n --list | grep '\[' | awk -vWorkDir="$GITHUB_WORKSPACE" '($2 ~ WorkDir"/cache/" && $1 ~ WorkDir"/openwrt/"){print $1}'`;do 696 | # sudo umount $path 697 | # done 698 | # sudo umount cache 699 | sleep 1 700 | sudo mount -o remount,compress=no,nodatacow,nodatasum /workdir/openwrt #openwrt 701 | # https://github.com/klever1988/nanopi-openwrt/issues/1158 702 | pv /dev/zero > openwrt/zerospace || true 703 | sync 704 | rm -f openwrt/zerospace || true 705 | sleep 20 706 | sync 707 | if command -v lsof 1>/dev/null;then 708 | echo '检测挂载点是否有进程占用' 709 | sudo lsof /workdir/openwrt &> /tmp/mount_pid.info || true 710 | awk '+$2>0&&!a[$2]++{print $2}' /tmp/mount_pid.info | sudo xargs -r -n1 kill -9 711 | fi 712 | sudo umount -f /workdir/openwrt #openwrt 713 | sleep 2 714 | # sudo losetup -l -O NAME -n | awk '$0~"/'${cache_name}'.img"{print $1}' | xargs -r sudo losetup -d 715 | sudo losetup -l -O NAME -n | grep -Eqw $LOOP_DEVICE && sudo losetup -d $LOOP_DEVICE 716 | # 偶尔消失,所以上面的判断 717 | #sudo losetup -d $LOOP_DEVICE 718 | sync 719 | 720 | export Avail_G_NUM=$(df -BG | awk '$6=="/"{print +$4}') 721 | 722 | bash -x ${GITHUB_WORKSPACE}/common/cache.sh upload 723 | 724 | 725 | # 缓存损坏或者初次缓存的时候,开启了 IB 726 | # 则再次 run 本次参数的 workflow 727 | timeout 5 gh -R ${GITHUB_REPOSITORY} run watch ${{ github.run_id }} > /tmp/watch_txt || true 728 | # 取第一个需要 rerun 的 job 名字,否则如果是 2 个没缓存的 matrix,只需要一个 job 去执行 gh workflow run 729 | first_rerun_job=$(awk '$0~/\(ID [0-9]+/{$1="";flag=$0};flag && $0~"gh-rerun-condition"{if($1=="-"){flag="";next;}else{print flag;exit;}}' /tmp/watch_txt) 730 | if [ "${CACHE}" = false -a "${USED_CONFIG_IB}" = true ] && echo "$first_rerun_job" | grep -qw "$JOB_NAME";then 731 | if [ "${{ github.event_name }}" == workflow_dispatch ];then 732 | echo '${{ toJson(github.event.inputs) }}' > /tmp/test 733 | workFlow=$( echo ${{ github.event.workflow }} | sed -r 's#.github/workflows/##') 734 | cat /tmp/test | gh workflow run $workFlow -r ${GITHUB_REF##*/} --json 735 | rm -f /tmp/test 736 | else # repository_dispatch 737 | curl -X POST https://api.github.com/repos/${{ github.repository }}/dispatches \ 738 | -H "Accept: application/vnd.github.everest-preview+json" \ 739 | -H "Authorization: token ${{ secrets.gh_token }}" -d \ 740 | '{ 741 | "event_type":"${{ github.event.action }}", 742 | "client_payload": ${{ toJSON(github.event.client_payload) }} 743 | }' 744 | fi 745 | fi 746 | 747 | if [ "${os}" = 'self-hosted' ];then 748 | gh auth logout 749 | fi 750 | fi 751 | 752 | - name: Delete workflow runs 753 | uses: GitRML/delete-workflow-runs@main 754 | continue-on-error: true 755 | with: 756 | retain_days: 5 757 | keep_minimum_runs: 7 758 | 759 | - name: Remove old Releases 760 | uses: dev-drprasad/delete-older-releases@v0.1.0 761 | if: env.UPLOAD_RELEASE == 'true' && !cancelled() 762 | with: 763 | keep_latest: 3 764 | delete_tags: true 765 | env: 766 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 767 | 768 | build_slim: 769 | needs: [set_matrix, build] 770 | if: needs.build.outputs.imageBuilder 771 | runs-on: ${{ fromJson(needs.set_matrix.outputs.inputs_json).os }} 772 | name: "${{ needs.build.outputs.build_target }}: ${{matrix.repo.name}}-${{matrix.repo.branch}} - ${{matrix.target}}" 773 | strategy: 774 | fail-fast: false 775 | matrix: 776 | target: 777 | - "slim" 778 | - "full" 779 | repo: ${{ fromJson(needs.set_matrix.outputs.build_repo) }} 780 | steps: 781 | - name: Checkout 782 | uses: actions/checkout@main 783 | 784 | # - name: install docker 785 | # uses: docker-practice/actions-setup-docker@master 786 | 787 | - name: prinf info 788 | run: | 789 | df -h 790 | lscpu 791 | free -h 792 | sudo sysctl vm.swappiness=0 793 | # slim/full 794 | echo 'target: ${{matrix.target}}' 'repo: ${{ toJSON(matrix.repo) }}' 795 | pwd 796 | ls -l . 797 | 798 | echo '${{ needs.set_matrix.outputs.inputs_json }}' > /tmp/github.json 799 | cat /tmp/github.json 800 | source build/common/scripts/start_set_matrix.sh 801 | 802 | # 容量满的时候强制推送,re run failed 然后拉取获取最新脚本 803 | real_branch=${GITHUB_REF##*/} 804 | if [ -n "${branch}" ];then 805 | real_branch=${branch} 806 | fi 807 | 808 | echo "real_branch=${real_branch}" >> $GITHUB_ENV 809 | git fetch && git reset --hard origin/${real_branch} && git clean -df 810 | 811 | echo "repo_name=${{ matrix.repo.name }}" >> $GITHUB_ENV 812 | echo "repo_branch=${{ matrix.repo.branch }}" >> $GITHUB_ENV 813 | echo "input_os=${os}" >> $GITHUB_ENV 814 | if [ "${{matrix.target}}" == 'slim' ];then 815 | echo "suffix=-slim" >> $GITHUB_ENV 816 | else 817 | echo "suffix=-full" >> $GITHUB_ENV 818 | fi 819 | 820 | - name: Initialization environment 821 | id: init 822 | env: 823 | DEBIAN_FRONTEND: noninteractive 824 | run: | 825 | if [ "${os}" != 'self-hosted' ];then 826 | sudo rm -rf /etc/apt/sources.list.d/* /usr/share/dotnet /usr/local/lib/android /opt/ghc 827 | fi 828 | # curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 829 | # echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | \ 830 | # sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null 831 | # 包管理偶尔会安装失败 832 | wget -q $(curl -s https://api.github.com/repos/cli/cli/releases/latest | jq -r '.assets[] | select(.name|match("linux_amd64.tar.gz$")) | .browser_download_url') 833 | tar zxf gh_*_linux_amd64.tar.gz 834 | find gh_* -type f -name gh -exec mv {} /usr/local/bin/ \; 835 | rm -rf gh_*linux* 836 | sudo chmod a+x /usr/local/bin/gh 837 | 838 | sudo -E apt-get -qq update 839 | sudo -E apt-get -qq install qemu-utils git gh gawk unzip patch autoconf automake upx wget curl rsync jq rename 840 | sudo -E apt-get -qq autoremove --purge 841 | sudo -E apt-get -qq clean 842 | sudo timedatectl set-timezone "$TZ" 843 | docker info 844 | 845 | # install github cli tool 846 | # 上传到latest分支 847 | if [ -n "${{ secrets.gh_token }}" ];then 848 | gh --version 849 | echo ${{ secrets.gh_token }} | gh auth login --with-token 850 | echo "::set-output name=gh::success" 851 | fi 852 | 853 | echo "DEVICE_NAME=${{ needs.build.outputs.build_target }}" >> $GITHUB_ENV 854 | 855 | cp -a build/${{ needs.build.outputs.build_target }}/* ${GITHUB_WORKSPACE}/ 856 | cp -a build/common ${GITHUB_WORKSPACE}/ 857 | # 设置一些给后续步骤作为判断条件或者执行的值 858 | bash common/env.sh 859 | ls -al . 860 | 861 | - name: Login to Docker Hub 862 | uses: docker/login-action@v2 863 | env: 864 | DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASS }} 865 | if: env.DOCKER_PASS != '' 866 | with: 867 | username: ${{ github.repository_owner }} 868 | password: ${{ secrets.DOCKER_HUB_PASS }} 869 | 870 | - name: Login to registry.aliyuncs.com 871 | uses: aliyun/acr-login@v1 872 | env: 873 | DOCKER_PASS: ${{ secrets.ALIUNCS_PASS }} 874 | if: env.DOCKER_PASS != '' 875 | continue-on-error: true 876 | with: 877 | login-server: https://registry.aliyuncs.com 878 | username: "${{ github.repository_owner }}@qq.com" 879 | password: "${{ secrets.ALIUNCS_PASS }}" 880 | 881 | - name: Download imagebuilder (Artifact) 882 | uses: actions/download-artifact@v2 883 | with: 884 | name: openwrt-imagebuilder-${{ needs.build.outputs.build_target }}-${{ matrix.repo.name }}-${{ matrix.repo.branch }} 885 | # 用前面job的输出会和本次对不上,用变量名才对 886 | #name: ${{ needs.build.outputs.imageBuilder }} 887 | path: . 888 | 889 | - name: Compile the firmware 890 | id: compile 891 | run: | 892 | bash common/imageBuilder-run.sh compile 893 | 894 | #make image -j$(nproc) PACKAGES='-luci-app-ipsec-vpnd' || make image -j1 V=s PACKAGES='-luci-app-ipsec-vpnd' 895 | echo "::set-output name=status::success" 896 | 897 | echo "FILE_DATE=$(date +"%Y%m%d%H%M")" >> $GITHUB_ENV 898 | 899 | - name: Organize files 900 | id: organize 901 | if: env.UPLOAD_FIRMWARE == 'true' && !cancelled() 902 | run: | 903 | cd openwrt/bin/targets/*/* 904 | pwd 905 | ls -lh 906 | echo "FIRMWARE=$(readlink -f .)" >> $GITHUB_ENV 907 | echo "::set-output name=status::success" 908 | 909 | - name: Do something after Compile 910 | if: steps.organize.outputs.status == 'success' && !cancelled() 911 | run: | 912 | cd openwrt/ 913 | set -x 914 | if [ -f "$GITHUB_WORKSPACE/$DIY_AFTER" ];then 915 | bash -x $GITHUB_WORKSPACE/$DIY_AFTER ${{ matrix.repo.name }}-${{ matrix.repo.branch }} ${{ env.suffix }} 916 | fi 917 | 918 | - name: Upload firmware directory 919 | uses: actions/upload-artifact@main 920 | if: steps.organize.outputs.status == 'success' && !cancelled() 921 | with: 922 | name: OpenWrt_firmware-${{ env.DEVICE_NAME }}_${{ env.FILE_DATE }}${{ env.suffix }}-${{ matrix.repo.name }}-${{ matrix.repo.branch }} 923 | path: | 924 | ${{ env.FIRMWARE }} 925 | 926 | - name: Upload firmware to release 927 | if: steps.init.outputs.gh == 'success' && !cancelled() 928 | run: | 929 | set -x 930 | cd openwrt/bin/targets/*/* 931 | [ -z "$firmware_wildcard" ] && firmware_wildcard=${{ needs.build.outputs.build_target }} 932 | build_target=${{ needs.build.outputs.build_target }} 933 | export build_target firmware_wildcard 934 | ls -lh 935 | bash ${GITHUB_WORKSPACE}/common/imageBuilder-run.sh release 936 | --------------------------------------------------------------------------------