-
In OneDev, you can add a job and have it triggered automatically when a branch is updated (check the triggers and params section of a job). Then you can add necessary steps to do what you want, including checkout code, running commands to call ssh to deploy files to your servers etc.
-
Previous Value Current Value Open
Closed
-
Do you have any examples of how to do this? I'm a bit stuck in trying to figure this out.
-
For instance I used below build spec to copy web site content to server via SCP, and then ssh to the server deploying the content:
version: 6 jobs: - name: Publish steps: - !CheckoutStep name: 'checkout ' cloneCredential: !DefaultCredential {} condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: build & deploy image: node:10.21.0 commands: - set -e - '' - npm install - node_modules/.bin/gatsby build - '' - mkdir /root/.ssh - chmod 700 /root/.ssh - '' - cat << EOF > /root/.ssh/known_hosts - '<known host string>' - EOF - '' - cat << EOF > /root/.ssh/id_rsa - '@secrets:private_key@' - EOF - '' - chmod 400 /root/.ssh/id_rsa - '' - scp -r public myuser@@myhost:/home/myuser - ssh myuser@@myhost sudo rm -rf /var/www/html - ssh myuser@@myhost sudo mv /home/myuser/public /var/www/html condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL triggers: - !BranchUpdateTrigger branches: main retryCondition: never maxRetries: 3 retryDelay: 30 cpuRequirement: 250m memoryRequirement: 128m caches: - key: npm-cache path: /root/.npm timeout: 3600Here
<known host string>needs to be replaced by host fingerprint of the server, and you also need to define a build secretprivate_keyholding a private SSH key able to login to the server -
Thanks for this @robin. Is there a way to set known host string and private_key as a variable stored on the project, so they're not saved into version control?
-
Here private_key is defined as a project secret (check project setting / build setting / job secret). The same can be done for known host.
-
Great. But how do I know what/where the directory is for the project? Here, you are copying the "public" directory to the remote/production server with SCP, right?
-
When run the step command, the current directory is root of repository if checkout step runs previously. And my "public" directory is a sub folder stored in the repository.
-
I've tried editing the buildspec, and this is what comes back whenever I add something other than just the version number (and I cannot commit if the version number hasn't changed):
Error parsing build spec io.onedev.server.buildspec.BuildSpecParseException: Malformed build spec at io.onedev.server.buildspec.BuildSpec$1.load(BuildSpec.java:82) at io.onedev.server.buildspec.BuildSpec$1.load(BuildSpec.java:72) at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3444) at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2193) at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2152) at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2042) at com.google.common.cache.LocalCache.get(LocalCache.java:3850) at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3874) at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4799) at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4805) at io.onedev.server.buildspec.BuildSpec.parse(BuildSpec.java:574) at io.onedev.server.web.page.project.blob.render.renderers.buildspec.BuildSpecBlobViewPanel.onInitialize(BuildSpecBlobViewPanel.java:80) at org.apache.wicket.Component.fireInitialize(Component.java:878) at org.apache.wicket.MarkupContainer.internalInitialize(MarkupContainer.java:1071) at org.apache.wicket.MarkupContainer.addedComponent(MarkupContainer.java:1048) at org.apache.wicket.MarkupContainer.replace(MarkupContainer.java:856) at io.onedev.server.web.page.project.blob.ProjectBlobPage.newBlobContent(ProjectBlobPage.java:845) at io.onedev.server.web.page.project.blob.ProjectBlobPage.onResolvedRevisionChange(ProjectBlobPage.java:1039) at io.onedev.server.web.page.project.blob.ProjectBlobPage.onCommitted(ProjectBlobPage.java:1467) at io.onedev.server.web.page.project.blob.render.commitoption.CommitOptionPanel.save(CommitOptionPanel.java:342) at io.onedev.server.web.page.project.blob.render.commitoption.CommitOptionPanel.access$100(CommitOptionPanel.java:67) at io.onedev.server.web.page.project.blob.render.commitoption.CommitOptionPanel$1.onSubmit(CommitOptionPanel.java:192) at org.apache.wicket.ajax.markup.html.form.AjaxButton$1.onSubmit(AjaxButton.java:113) at org.apache.wicket.ajax.form.AjaxFormSubmitBehavior$AjaxFormSubmitter.onSubmit(AjaxFormSubmitBehavior.java:218) at org.apache.wicket.markup.html.form.Form.delegateSubmit(Form.java:1312) at org.apache.wicket.markup.html.form.Form.process(Form.java:976) at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:797) at org.apache.wicket.ajax.form.AjaxFormSubmitBehavior.onEvent(AjaxFormSubmitBehavior.java:174) at org.apache.wicket.ajax.AjaxEventBehavior.respond(AjaxEventBehavior.java:155) at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.onRequest(AbstractDefaultAjaxBehavior.java:601) at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.wicket.RequestListenerInterface.internalInvoke(RequestListenerInterface.java:258) at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:241) at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.invokeListener(ListenerInterfaceRequestHandler.java:248) at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.respond(ListenerInterfaceRequestHandler.java:234) at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:955) at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64) at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:288) at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:245) at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:316) at org.apache.wicket.protocol.ws.AbstractUpgradeFilter.processRequestCycle(AbstractUpgradeFilter.java:70) at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:203) at org.apache.wicket.protocol.http.WicketServlet.doPost(WicketServlet.java:159) at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at io.onedev.server.web.DefaultWicketServlet.service(DefaultWicketServlet.java:43) at io.onedev.server.web.DefaultWicketServlet$$EnhancerByGuice$$b27a4b57.CGLIB$service$2(<generated>) at io.onedev.server.web.DefaultWicketServlet$$EnhancerByGuice$$b27a4b57$$FastClassByGuice$$122b7d63.invoke(<generated>) at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:76) at io.onedev.server.persistence.SessionInterceptor$1.call(SessionInterceptor.java:23) at io.onedev.server.persistence.DefaultSessionManager.call(DefaultSessionManager.java:79) at io.onedev.server.persistence.SessionInterceptor.invoke(SessionInterceptor.java:18) at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:78) at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:54) at io.onedev.server.web.DefaultWicketServlet$$EnhancerByGuice$$b27a4b57.service(<generated>) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1626) at com.google.inject.servlet.DefaultFilterPipeline.dispatch(DefaultFilterPipeline.java:47) at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at io.onedev.server.git.GoGetFilter.doFilter(GoGetFilter.java:87) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at io.onedev.server.git.GitLfsFilter.doFilter(GitLfsFilter.java:440) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at io.onedev.server.git.GitFilter.doFilter(GitFilter.java:330) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61) at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108) at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66) at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:450) at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387) at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at io.onedev.server.util.jetty.DisableTraceFilter.doFilter(DisableTraceFilter.java:28) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:763) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:516) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:386) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException at io.onedev.commons.bootstrap.Bootstrap.unchecked(Bootstrap.java:363) at io.onedev.commons.utils.ExceptionUtils.unchecked(ExceptionUtils.java:35) at io.onedev.server.migration.MigrationHelper.migrate(MigrationHelper.java:151) at io.onedev.server.migration.VersionedYamlDoc.toBean(VersionedYamlDoc.java:61) at io.onedev.server.buildspec.BuildSpec$1.load(BuildSpec.java:80) ... 122 more Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedMethodAccessor272.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at io.onedev.server.migration.MigrationHelper.migrate(MigrationHelper.java:149) ... 124 more Caused by: java.lang.IllegalStateException at com.google.common.base.Preconditions.checkState(Preconditions.java:494) at io.onedev.server.buildspec.BuildSpec.migrate5(BuildSpec.java:720) ... 128 moreI can still edit. Deleting the file and starting again does the same thing.
-
Just copy the build spec as is to OneDev build spec editor (edit source), then switch to edit tab to edit it.
-
I honestly did, and it broke when I edited it. Even re-pasting it as is didn't work, nor pasting in a new file.
So I deleted it and started from scratch using the UI. There is little going in terms of documentation and understanding, because copying that made a job run, but following another guide you created involves creating an agent (which I didn't do before).
-
Not sure what happens at your side. But I just copy the content, and then switch to "Edit" tab to change things. Everything works fine. Generally you should not edit the build spec source directly.
-
Okay, I've basically got this working again, and I have a better understanding. However, once broke, the file needs to be deleted again and then recreated.
-
@robin I am now facing an issue in creating a directory. I don't think it's a OneDev issue, but maybe you can help?
I can't
scp .due to security issues, so I'm trying rsync, which I've used before. However, I get "permission denied" when try to create a directory. I tried echoing out $USER, but it returns as blanked out (as though a password); I had hoped to check the user and make sure they have the correct permissions. The dir secret also returns as the blanked string:rsync: mkdir "/var/www/html/*****_tmp" failed: No such file or directory (2)It fails each time I get to the Upload step, due to the permissions issue.
version: 15 jobs: - name: Deploy to Staging steps: - !CommandStep name: SSH Agent runInContainer: false interpreter: !DefaultInterpreter commands: - eval $(ssh-agent -s) - echo "@secrets:private_key@" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh - chmod 700 ~/.ssh - '' - echo "@secret:known_hosts@" >> ~/.ssh/known_hosts - chmod 644 ~/.ssh/known_hosts - '' - echo $USER useTTY: true condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CheckoutStep name: Checkout cloneCredential: !DefaultCredential {} withLfs: false withSubmodules: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: Upload runInContainer: false interpreter: !DefaultInterpreter commands: - echo "$USER" - mkdir -p /var/www/html/@secret:dir@_tmp - rsync -rav -e ssh --exclude='.git/' --exclude='*.gitignore' --exclude='*.yml' --exclude='*.sql' --exclude='gulpfile.js' --delete-excluded ./ @secret:user@@@@secret:ip@:/var/www/html/@secret:dir@_tmp useTTY: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: Backup runInContainer: false interpreter: !DefaultInterpreter commands: - echo Create a backup from current files useTTY: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: Copy runInContainer: false interpreter: !DefaultInterpreter commands: - echo Move the files to the server useTTY: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !CommandStep name: Cleanup runInContainer: false interpreter: !DefaultInterpreter commands: - echo Remove the previous versions useTTY: false condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL retryCondition: never maxRetries: 3 retryDelay: 30 cpuRequirement: 250 memoryRequirement: 128 timeout: 3600 postBuildActions: - !SendNotificationAction condition: always receivers: user(classicniall) -
I am not familiar with rsync. It might be easier to make your script working out of OneDev first.
-
Okay, I am getting somewhere. I'm rebuilding it all, and testing out all the commands.
I do get this:
sudo: unable to resolve host *****: Name or service not knownWhen I run this command:ssh @secret:user@@@@secret:ip@ sudo mkdir -p /var/www/html/site_tmpHowever, the directory is created.
| Type |
Question
|
| Priority |
Normal
|
| Assignee |
Not assigned
|
I've got many WordPress sites that I like to automate.
I come from a Gitlab background, and their documentation for CI/CD isn't the best, and I managed to cobble together something that has managed to work. Basically, it's a bunch of SSH commands (so I don't have to manually copy and paste each line whenever I need to deploy). This ran whenever a designated branch was updated.
Now, what would be the best practice in order to do the same, and how to watch for those changes (i.e. push to Staging branch to update Staging server)? I generally don't use build or version numbers (knowing that is an option), because I don't really know how to use them effectively.
Below is what I used (and I used Gitlab variables too):