 Welcome, this is DevOps Leads the Way to Better Drupal Development. Today I'm gonna talk to you about DevOps and your development and how DevOps is related to your development and how DevOps can improve your development. I'm gonna talk to you about a conversation that the Drupal community has been having for several years now that can be summed up pretty simply in this question. Where is your repo? I'm going to go through that argument and present, simplify it down to basically two sides. I'm gonna talk about the pros and cons of each approach. And then I'm going to explore how we might actually not have to accept either of those approaches and come up with a third way that gets the best of both worlds. I'm gonna walk through that, show some actual code of how it might be done and time permitting, go through a demo of some things I've been working on. So my name's Kevin Champion. I am a independent contractor and developer. I've been working in Drupal for about four years. I prefer to be barefoot almost always. A little trivia fact about myself have now successfully run and completed two marathons, completely 100% barefoot. So I want you to think about your typical Drupal site, your typical Drupal project. If you have a lot of variance in the types of projects you end up doing and you do a lot of strange custom stuff, just maybe focus on the last project that you did. So how many of you puts your Git repo in your Drupal route like this picture shows? Raise your hands. How many of you has this typical practice? So you put your Git repo in your Drupal route, you track Drupal core, all the application files, all of your custom code, pretty much everything in there. This approach has many benefits and a few drawbacks, which I'll talk about in a minute. How many of you do something a little bit more complicated like this? So you set up a parent directory. Inside that parent directory you have actually your Drupal route, which has Drupal core and all of your custom code. And you also have these other things. It varies from project to project, but you have other things that you want to track in your repositories. You sort of take it one level up and you put your Git repo in there, you track everything and then Drupal route. Show of hands. All right, so that's not quite as much as the first one, but still quite a few. How many of you do something like this where you would put your Git repo for your site inside your sites directory, either covering all of your sites or just like one specific site? Show of hands. All right, very few on that one. And lastly, how many of you put your repo inside of an install profile? So you set up an install profile as the container for your site and your repo is in there. All right, even fewer. So this one's got the least. So DevOps is critical to development. This probably isn't news to you, but the way I mean this, I think is a little bit different than the way this phrase might normally be interpreted. What I mean to say DevOps is not separate from development. It's not a separate process that's just there to help with development. It's not just something that you don't really worry about until you've developed your site. Client's pretty happy and then oh, we've got to do the DevOps stuff to get it to the place where it needs to be so that it can be deployed. It's not just deploying your code, your site from environment to environment. DevOps is farther down the stack than you might ordinarily think about it. I'm here to say that DevOps is critical to how you develop the very process with which you develop to the nature of your development. And for this reason, where you put your repo is really, really important. One of the reasons why it's important if we just sort of take a pause for a moment and think about Git, and this is really specific to Git. So this is something I've been reflecting upon. It's really amazing to think how much software in general has changed and the Drupal community along with it in a really short amount of time because of the creation of Git and the adoption of Git and how it's taken off. You can't really even imagine using other version control in most cases nowadays, which is quite remarkable. Git itself baked into the very way that it works, the very structure of the core of how it operates. It really has two fundamental purposes. You normally think, maybe, you normally think about Git as source control as change management. And that certainly is something that it excels at. But built into the way that it works and the way that Linus Torvald's built it was also sort of, you might think of it as a DevOps component. So Git is not just good for tracking changes, merging changes. Git's also really good for moving code from one place to another. There's a really great video of Linus introducing Git in a Google talk in 2007 to Google to try and encourage them to use it. And in that talk, he describes what he had in mind when he was creating it and the team of developers that were creating it. And one of the most important things about it was that it was not a centralized system. It was peer-to-peer. It had to be super fast, which meant that he could connect to another repository somewhere else in non-centralized location and move code back and forth between it in a really efficient and powerful way. So the two camps I'm going to, like I said, simplify the argument that Drupal's been having about this are sort of simplified down into two different camps. The first one is camp, what I'm calling, Camp Keep It Simple. So Camp Keep It Simple is the first version. I would venture to guess that like 90% of all Drupal projects that are using Git are probably using this approach. They put their Git repo in their Drupal root. They're tracking almost everything in there. Everything except for a settings PHP file, maybe your actual site files. This approach has a ton of good stuff going for it. So first and foremost, it's really, really simple. This is probably the most intuitive thing. It's the thing that people think about when they're like starting up a project of where am I gonna put my repo? Okay, they're gonna put it in the site root. So that's really simple approach. It comes with a lot of benefits. And one of the great benefits is that it makes DevOps really easy. So moving your code from one environment to another is really simple because it's all right there in that one repository. You have minimal additional setup for each subsequent environment. And one of the, as a part of that, or component to that is that when you're working on a team of people, team of developers makes it really easy to share changes, to track, to work with each other, to make sure that everyone's working off the same code. And then lastly, a sort of side benefit is that when you're tracking everything in one repository like this and you do have other environments set up, and a change happens in one of those environments, you are tracking it so that you can debug it and figure out what, if a file is changed, that's causing maybe the problem that you're seeing. Now, to introduce the other camp, as I'm putting it, I first need to reference a post that James Walker wrote back, all the way back in 2011. In it, he sort of introduced a probing question. He had done a lot of work with install profiles in the past and going all the way back to very early versions of Drupal. And had always liked them and the reason why is because he felt like an install profile can actually perfectly encapsulate what it is to be a Drupal site. So he writes this post called, saying every Drupal site is an install profile. And what he means by that is it is an install profile because an install profile can hold and contain everything that makes up an individual Drupal site. And if we think about that question, what makes up an individual Drupal site is usually a theme, some custom code, usually inside of modules, and a list of libraries and contrib modules. Note I say a list, it's not even actual contrib modules. That's not unique, what's unique is just the list to that site. So this post inspired me and many other developers to begin, got the wheels turning, got us thinking about this a little bit. So the other side of the argument is what I'm calling camp only what you need. So this camp says, okay, an install profile can be used as a container for an individual Drupal site. So we should put our Git repo in that install profile and only track what's in that install profile. It's only what you need because it's not tracking a whole bunch of other stuff that is not unique to that Drupal site. So this approach has its own set of unique benefits. It's more efficient, there's less code to track which puts less of a load on Git. Now Git so fast that you don't actually, that's not really that relevant, it's not that important. But it's not just that it's less, it's that what you're putting in this repository is gonna be more semantic than what you're putting in your other repository because this repository is the stuff you're interested in. This is the stuff that's different about this site than any other site. Whereas when you're using the other approach, it won't always be that way. Now it also comes with the benefit that you can set up a structure so that you can have other repositories. So let's say a custom module and it can have its own repository. Using this structure, we actually have a framework where we can incorporate that sort of change. So just to go over some of the basics here, this is what an install profile might look like. So an install profile looks a lot like individual site directory but it also looks a little bit like a module. So inside of a sample install profile, you're gonna have a directory for your modules, directory for your themes, probably a directory for your libraries, although not shown here. And in this case, a directory for patches. And then you're gonna have an info file. You're gonna have a .profile file which is essentially the same thing as a .module file if you're creating a custom module. And then you would likely wanna have a .install file which is the same as you would use an install file in a module. There's two other files in here that make an install profile and install profile. And those are these two .make files. You won't always see two but you're likely to see a .make file. And that's because you have to have a separate process when you're using an install profile architecture to run site builds and you use those make files. So what's important about looking at an install profile is specifically what's not in that repository. So you see here, Drupal Core is not in that repository. We don't need to track it. Your libraries are most likely not gonna be in that repository unless for some strange reason you're developing your own library in that project which is probably poor practice anyway. And your actual contrived modules are gonna be excluded via a get ignore that you'll set up from that because you don't need to track that code. You don't need to track those contrived modules. You just need to track the list of contrived modules. As I mentioned, this is because you have to run a build process. So those make files are build files and a build file is essentially just a configuration file. In the configuration file, you set up a list of what you want to be built out when you run the build. So this first one is an example of what would be called maybe the profile build file and it's very simple. All it has in it is it lists the version of Drupal Core and then it's gonna list the actual profile which is your container for your site secondly. So there are many different build tools but the one I'm gonna talk about today is called Drushmake. Can I just get a show of hands for everyone who is familiar with Drushmake and has used it before? Okay, good. So that's most of the people. So example Drushmake command, you would build the file and then you would pass it the parameter where you want that file to be built. This is the other build file that was a sample and solve profile. So this is a drupal-org.make. The name of that's very specific and it's specific because Drushmake in the internals, it recurses through all the projects that it builds out. So when you define one project, it builds it, retrieves that project and then it'll traverse the directories and the files in that project looking for any files named drupal-org.make or the name of the project.make. And when it finds those, it then tries to build those files too. So when you run build on the first file, it's Drushmake's actually gonna pick up this file as well and parse this and then attempt to operate on it. So you see here, this is defining out the items that are gonna be unique to the site. We have a list of contrived modules, admin menu, libraries, path auto. These we don't actually have to specify very much to them because it knows to go look for them on drupal-org and then it will actually download a tarball and it will unarchive that. Down below we have a custom module. This custom module, if you pay attention to the download type, we can actually specify git as the download type, pass it the URL to our repository and give it a ref, in this case a branch name. And what it'll do is it'll actually clone that repository as its default technique for pulling in that code. So immediately when you think about using the install profile approach for your git repository and setting up your site using that as a container, you immediately have to think about builds because builds are a component part of setting things up that way. So the first thing that you probably think of is okay, now we have to introduce a build process to our development process. And that process might look something similar to this. So you download your make file from your repo, your remote repo, you would run the build using Drushmake in this case. You would perform your development just like you would ordinarily. With the caveat that you would have to understand where that development needs to take place. So it would be in your install profile rather than in the site's directory. You'd follow whatever your git flow is that you work with to incorporate your changes, get them merged. And then when you suspect that there's upstream changes, you would have to run a new build. So this process on the face of it isn't much to talk about. In fact, I think this is probably similar to what a lot of developers in other languages and frameworks end up doing because of the nature of that technology. So this is the problem space. This is the conversation that's been happening. You have two different camps in the Drupal community. The first one is Camp Keep It Simple. I'm labeling them the pragmatists. They want things to be simple. They don't want any additional headaches and they feel like this does the job well. The other is Camp Only What You Need. They're, I'm labeling them the purists. So they are the engineers and the architects who really like the fact that they actually, they don't like the fact that in the other model you end up tracking a bunch of stuff that you're never actually concerned with. That irritates them. So they're usually very taken to the other approach because it's really paring it down to only what you're concerned about. Now we talked about the benefits of these. They both have some significant drawbacks. So with Camp Only What You Need, you have to run builds. This is actually a really significant drawback. It introduces complexity into your development process if it's a part of your development process. And that complexity can be enough to actually give you reason not to use it. Camp Keep It Simple on the flip side. Despite its simplicity, it actually can undermine our own development efforts. Drupal itself is a modular architecture. It's based on the idea of having component parts that you can build independently and reuse them elsewhere. When you put your Git repo in the site route like that and you're doing your development, assume that this is a site of sufficient complexity that you have custom modules. Assume that some of these custom modules are actually significant, that they take you some time to develop and they're not just one-offs. Well, those modules that you're developing then are stuck in that history of that parent. Now you can get around this and the way that you would do that is you would just throw your Git repo for your particular custom module that you're developing and doing significant effort on inside wherever that resides, so in your modules directory of your site and throw that Git repo in there. And then if you do that, you're effectively using Git submodules. So real quick, does anyone really love Git submodules and or Git subtrees? And okay, does anyone use them? Does anyone love them? All right, all right, so we got a couple, two, three people. So for you all, you may have contention with some of the things I'm saying. I'm not gonna go into either Git submodules or Git subtrees. It's enough for me to say that I don't think that they're a viable strategy for development across the board. I think that they can work really well for people to understand them really well. And I think that actually means that for a lot of people working on teams where you can't expect that your team members are gonna have a certain level of expertise, it's not really an option for architecting your site. So Git submodules and Git subtrees are I think prohibitive tools. And that presents a huge, huge problem because I think it undermines our ability to develop really well using this model. So what really is the difference between these two? Well, if we talk size, I took a recent project and did a quick rough, ran some analytics to do a quick rough comparison. So I had one project the same code base and I had to get repository located in the site root and I looked at how many files there were and how many lines of code and then I did the same for the same project, the same code base but with the Git repository in the install profile. And you see here that there are over 9,000 fewer files, over one million fewer lines of code cumulating into a 93% difference. So this is significant. Now you might say it doesn't matter. I would suggest that a smaller code base likely means a little bit less complexity. It likely means a more maintainable code base but that's definitely not a rule. I think more important for me is the semantics of what's tracked in the Git history. So when you have the smaller code base and you're only tracking what's unique to that site, when you commit a change, let's say you're updating a module, the difference is that you're changing a make file, you're changing the version number, which to me is semantically sound to what you're actually doing there. The alternative is you're updating the module, you're actually updating the files and those files, the changes in those files get tracked in your history, which isn't true to what you're actually doing there. So I said camp only what you need, I'm labeling them the purists. The benefits of the purists is that you have an opportunity for everything to have a place and for everything to be in its right place. The big gain here, the big win and the one single thing if you don't take anything else away from this session that I hope you take away is that this allows you to develop with reusable components and reusable components are really, really important. That's what Drupal is from the ground up and that's really important for us to be able to use that same approach in our own development. So the ability to write a custom module that you can reuse with let's say the same client on another site, the ability to write a custom module that you can reuse across all of your clients and all your projects, perhaps most importantly the ability to write a custom module that you can easily contribute back to the community. I actually would argue that because the way that we have been setting up our repositories in most of our projects, we have less contribution back to the community because there are so many custom modules, so many lost ideas that get stuck down in individual projects. So how many of you have been developing and you're writing a custom module and you knew that it could be abstract, it could be reusable, you could use it later, you maybe even wrote it that way, you maybe even took great pains to write it that way. But you had your project set up the other way so that the Git repository was in the Drupal route and so all of your commits and all of your changes were tracked in the overall project history and you never actually got back to going back in there, grabbing that module out, rescuing it from the depths of that project and reusing it. How many have had that happen to them? So how many of you have actually gotten over that problem and gone and grabbed that code and then you've started a new repository and you've been really frustrated by the fact that you did a ton of work on that module, but the history of that, the Git history is all wrapped up, the changes is wrapped up in the larger project and now you have like a new repo and you have like a single commit that says, okay, here's my module. How many of you have had that situation? So that's irritating and it's not good design and ideally we shouldn't be doing things that way. So the way that we set up our projects I think is really important. I do not think that this is a trivial distinction. So some would argue that this is bike shedding, that this is going through and saying that this is just a subtle change, it doesn't really matter one way or the other. I think that it's really important because I think that when we set up certain structures, any structure actually, when you have any architecture it influences the way that we do things. So setting up and having an architecture it biases us in a certain direction. It sets defaults for how we do things and I think that nudges the way that we end up developing and I think that is really important. When you set up things with using an install profile as the container for your site, you end up having to think about context. You actually enforce by that simple distinction you already immediately enforce your developers to think about context. They have to think about whether or not what they're developing fits inside of the current site that they're building or if it's more generic than that. That subtle distinction is really important. I was in a situation where I was working with a team of developers on a project and we had this sort of can't keep it simple approach. We had one project that was like that. We made the decision to switch to another approach and immediately when I was in the position of project lead and I was working with other developers new conversations started to happen that never happened before with them. It usually was like here's a geotask, here's the issue, here's the feature that the client needs. You need to build this type of module and I think that you should build this in a reusable way because we may find use for it later. That was what I would tell them. And what happened immediately when we switched this architecture is those questions started to come at me. They came flying at me from the developers themselves saying, listen, I know that this module and this feature is such and such and I think actually we could maybe use this should I build it this way so that it's actually in its own repositories that we can reuse it later. I think that's an important distinction because it proves to me that developers then was thinking in a different way than we were previously. And if you can't tell, I think in general that the install profile as a container is the way to go. I prefer it and I think it's a better approach. But I know probably half of you in here are saying, hold on a second, let's not just gloss over all the negatives. And there are some really significant negatives. The build process itself is hellish. For those of you, which was most of you, have used Drushmake before, it's not a very simple tool to use. In fact, it has a ton of configurations and flags and it also at least in a lot of developers' experience is quite buggy. You get inconsistent results when you run it different ways and it takes a certain on ramping to get up to speed where you're really comfortable using it. So at minimum, it introduces this build process, introduces extra steps. It introduces extra time because of the extra steps, but also because Drushmake oftentimes when you have sufficiently sized site actually takes a while to run. It takes a while to run in part because it can be a processor intensive process so depending on the resources that can be prohibitive as well. It's also inherently flaky. So how many of you have run Drushmake and it was a significantly sized site and you were running the build and the build takes like seven, eight, 10 minutes and you ran that build and you thought everything was fine, but some site from some library that you were trying to download was down at the time. So it didn't download that and it failed and you lost all the completely lost the build and you had to start all over. How many have been in that situation? Yes, that's, yeah, that's not a good one. So it's inherently flaky because it has to go out. It is going out for you and downloading all these resources from all these different places that you've defined in your build files. If any of those is not available, it's gonna fail. Now there are flags using Drushmake. You can prevent it from failing completely so you have the result of what it's actually retrieved but the point is that it is an inherently flaky process. That makes it difficult. Drushmake and running builds using Drushmake is actually hard to learn. I've learned this by experience, by picking it up myself, figuring it out, then trying to teach others and having to listen to all the ways in which it's really difficult and hard for them to incorporate into their development, into their flows and even just understanding basic principles about what a build is, why we need to run it and what it's doing for us and why that's could be a benefit. It introduces a significant team dilemma. Part of that's because it's hard to learn, a big part of it. So if you have a new developer or a junior developer coming onto a team and you're trying to get them up to speed and they're not used to this, they haven't ever developed like this before and you need them to be developing and producing results rapidly, you may find that this actually is a big, big barrier to that. I've been in a situation just like this where it created a huge headache but it's not just new and junior developers. If you're working on a team where you actually have a division of roles, let's say you have a themeer that comes onto your theme work, themeer comes on at some point in the project and now they have to get up to speed with this whole build process which is something that for a themeer skill set, someone who's dedicated to theming is not in their real house and that can make it even more prohibitive for them. I've also been in that situation and lastly it creates a significant devops headache because you're not tracking all your files, moving those files and moving that code from environment to environment isn't so easy anymore. At minimum you're gonna have to run builds in each environment that you want that code to exist on. When you think about development environments, your working environments, it might not be a problem. When you think about running that on a production server, I don't know, maybe there are good flows that make that work but for me I know I could never stomach doing that because of its inherent lack of reliability. So the big question I have and the big question that I challenge you all is can we be pragmatic purists? Can we take the best of both of these worlds? So can we take the benefits, the pros from the simpler pragmatic approach and the benefits from the more pure architecturally sound approach and come out with something where we benefit across the board? The answer is yes. I tell you it's yes. So there's an animation running so you can just loosely pay attention to it. I'll walk through it in a second. The way that we can make this happen, the way we can be pragmatic purists is by separating out the build process from the development process. So the flow diagram I showed before is a red herring. When you include the build process into the development process, it's not solving the problem. Again it can solve the problem for the developer who understands Drushmake in and out, who understands the build process in and out, who knows how to run targeted builds, who knows how to work with it, that's fine. But most often for most of us we're not isolated and we're working with lots of other people and we want to be working with lots of other people for those situations it's not really viable. So if we separate out the build process from the development process and the reason this relates to DevOps because in my mind the build process is a DevOps process. So this here is an animation showing roughly the time it's sped up probably two and a half times but it's roughly the time it takes for me in this case to go in make a change to a make file where I want to pull in a new custom module. So I add that custom module to the make file, commit that change, I push that up to the server. Server magically triggers in this case a build server. Imagine a build server at this step where it's at right now an automated build is running for me on the build server. It takes a little while. When it's complete, let's say I have Jenkins set up I have the UI for Jenkins, I know it's complete. So then I know I can pull down my latest changes. So I'm able to pull those changes back down from the build server which is running the build for me. We never have to run a build locally and when we get through to the last step you'll see it's just showing the new custom module that was downloaded. So yes, I think it's possible to do this and I'm gonna walk you through how I think it's possible. The problem before was this, I think is the wrong approach. When you just incorporate builds into the dev process it doesn't end up working out. There's huge complications. If we simply separate them this is nothing more than a conceptual shift that has real world ramifications but a conceptual shift. If we separate them and we say, okay development process is development process the build process is dedicated to a DevOps component a separate process. This allows us to be able to have a situation where your developers then don't necessarily always have to understand the build process and know how to run it themselves. So on left you have the dev process it looks very ordinary, you develop just like you normally would and use your get flow. On the right in this case like I just illustrated in that animation you have think about having a build server the idea of a build server. That build server downloads the make file runs the build and then let's say it serves up the build as a result and a V host on that server and call it your dev environment your test environment whatever. So you've developed, you've pushed it up that trigger to build and now you have a new environment that's built for you that can go and test and look at. Just by making this simple conceptual divide we already knock off the top four items from the problems, the hellish experience of running builds. So these are all sort of the system level problems the additional steps, the time it takes to run them how intensive the processor is and how inherently flaky it can be just because we're saying okay let's outsource this problem to an automated build process on a dev server. That simple conceptual shift it doesn't actually address how hard it is to learn this whole approach and the architecture behind it the team dilemma and the devops headache so it doesn't address those at all for instance in this previous example on the left this is overly simplistic right the developer is developing they're pushing the changes and then the builds running and then you have this test environment but then the developer's local environment is not necessarily in sync with what's up on the test environment. So I'm here to suggest we add an additional layer in here to add a little complexity make the devops process a little bit more robust which can open up doors to helping us solve this problem and get the best of both worlds and I'm gonna introduce this in part based on what I was saying earlier about the nature of Git the reason why I think this is a viable strategy is because Git has these dual functions I was introducing these concepts to a friend of mine a developer friend of mine who is wiser than I and more experienced and he was wondering why the heck I wanted to do this why I wanted to use Git in this way and I told him it's because of the fact that Git inherently is a good tool for moving code around from environment to environment. So I'm gonna separate out in two different slides now the dev and the devops side this is the devops side I'm gonna say let's say a build is triggered somehow we have a trigger set up let's say you push code and that triggered a build on the devs on a separate server on a separate environment on a build server the build's triggered it downloads the make file it runs the build and then critically it takes the result of that build commits it to a brand new repository that has no relation to the other repositories you're using it's one off sort of this repository I'm gonna call the builds repo it only has the complete result of the build and then from there you can deploy by just pulling from that repo so you deploy that view host for your test environment but also you can imagine that you can deploy anywhere else as well if we do that then our development process is also ironed out so we can develop just like we normally would use whatever your Git flow is if you detect our upstream changes you can then just pull the latest build down from that builds repo that you've committed the result of the build on the build server with okay so we're just adding one little component it shifts the whole game now upstream changes when you're working in this sort of install profile as a container and running builds and having make files it's not actually as simple as you ordinarily would have upstream changes and wondering about whether or not there are upstream changes and checking to see if there are upstream changes because of the fact that just make recurses so you don't actually know necessarily if a new version of a module was introduced somewhere down the chain so it becomes a little bit more difficult so if we do this there's the potential to eliminate all of the building problems in one since we outsourced them to this concept of a build server but we also introduced benefits to the rest of the process okay so we solve the DevOps headache by actually committing the result of the build to its separate repo that we can then deploy from we at the same time can solve the development headaches by being able to pull those changes down to your working environment and work from the result of the builds okay so I'm gonna go ahead and do a deep dive and get into the actual code of what this might look like all right so there are six rough six steps here and I'm mostly focusing on the build the DevOps component of this so this notion of setting up a build server it wouldn't actually have to be a separate server you could do this locally the first step is to set up the build server directory structure and one big big caveat there are a million ways to do this like most of the things that are good this started as a series of bash scripts this was reflection of choices I made you could do this any number of ways so just keep that in mind if you end up liking this approach you wanna implement it down the line but it doesn't quite fit your use case and how you wanna do things no problem just alter it to fit so let's say you have the V host section of your server in that V host section you're gonna have a container directory here that I'm calling your site inside that you're gonna have actually the directory that is your V host for an environment in that directory you're gonna end up having an actual Drupal install and it's gonna have a get repo in it you're also gonna have a build directory which is gonna have a get repo in it and lastly you're gonna have a third directory for the builds repo the builds repo is going to have a headless get repository in it this step in particular when I just mentioned that caveat having a headless repo on your server absolutely not necessary you could set it up as a GitHub repository or whatever tool you use to manage your code you could put it wherever you want in this case for me it was not something that needed to be have the extra tools around being more visible and the extra workflow type tools that GitHub provides so it made more sense to just have it be sitting on the server as a headless repo is headless repo how many everyone are familiar with the headless repo more or less who's not anyone brave enough okay okay good so I'll explain it okay so you normally have your get repository if you've ever paid attention to what get when you run get init for instance if you pay attention to what happens when you do that it actually sticks a directory a hidden directory in wherever you ran it called dot get that dot get is where it stores all the magic happens in there that's where it's storing all of the changes that it's tracking for you okay when you create and that allows you because it's a hidden directory inside the directory that allows you to track your files your actual working files when you create a headless repository you're saying I don't need to track any working files all I want is the get component of it so this is a technique that you can use if you're trying to set up for instance your own remote that you're gonna bounce off of back and forth it's like a poor man's github you might consider it and there's other tools that actually take off this idea and build tools around it so you don't have to use github and a lot of people probably use those so when you look inside it when you set up a headless repository you look inside it all you see is the system the get system files in there you don't actually have a working directory to track changes all right so the first step here all we have these are just make-ters so just create these three empty directors is all it is so the first step is inside the builds repo directory we're gonna create that headless repo you do that by just attaching this flag dash dash bear get init dash dash bear that sets up your headless repository now we're gonna shift into our build directory we're gonna initialize a new repository there we're going to create a getignore you could just copy this from any other site that you have a getignore in your Drupal root or use whatever getignore you want there so we're gonna create a getignore add it commit it as the initial commit to the repository get branch dash m that just changes the default master branch to a branch name that we want to use totally optional here seven dot x dash one dot x dash builds we're gonna add a remote the remote we're gonna add is actually to that headless repository we just created so on the same server in this case you're just gonna pass in the path to that directory and then we're gonna push this one commit with this getignore file to that headless repository so now the builds directory has a single commit and the remote headless repository has a single commit we're gonna go into the vhost directory we're gonna initialize a repository there as well these are all setup steps mind you we're going to add a remote to the headless repository we're gonna pull down that commit that we just made on that headless and then we're just gonna for convenience sake change the branch name again to that branch that we wanna use by default it would be master so these are sort of infrastructural steps then we're gonna get to the point of where the magic happens we're gonna run our first build roughly speaking these steps could look however you want but you would download the build file which you probably wanna store in your repository for your install profile and we're gonna actually just destroy the build directory that we just created because one of the things that Drushmake does is it requires that in order to build a site from Drupal root down it can't have an existing directory already there if anyone knows more about Drushmake or like if anyone else has had this problem or knows more about it than I do I would love to talk after because this simple fact actually is sort of gets the ball rolling for a bunch of other work rounds that end up having to do with all this stuff so gonna remove that build directory run your Drushmake into a directory called build which is the same name of the directory that we just removed if Drushmake is successful it will successfully build out the entire site including all of Drupal core files and your entire site structure then the really difficult part comes where we're gonna try to take the result of that build and we're gonna commit it to the build's repository so this first step you don't really need to understand what the first command does here but technically but essentially what it's doing is it's removing any lingering get ignore files that may be in the result of the build so that new build is gonna remove any get ignore files and that's there because Drushmake has a flag called working copy that you can run and when you run working copy it'll actually clone it by default does this to download the files it'll clone the files if you define in your make files a get repository it'll actually use like get clone to clone those and that'll clone the repository normally if you don't have the working copy flag it'll delete that directory and it'll delete that repository but if you do have the working copy it'll leave that there what it doesn't touch is the get ignore files and get actually does deal with get ignore files that aren't in the root where the get directory actually is so it'll actually affect your results of what you're able to track so the first step remove all those get ignore files they're just gonna cause a headache we're gonna initialize a repository now because we've built out a new build it doesn't have any get information it doesn't have any get repository in it we're not using working copy in this case so we initialize a new repository we add the remote back to the builds repo we're gonna fetch from that builds repo and we're gonna check out the get ignore file the new result of the build doesn't have a get ignore file in it we're gonna grab that get ignore file that we committed earlier we're gonna add everything so the result of the build including the get ignore file the tag command there just is creating a timestamp that we can use in our commit message again this is, I guess this is bash so just you can translate these steps into whatever language you're more comfortable thinking so we're gonna commit that result and then we're going to go ahead and check out the branch that we set up initially this is where things get really hairy we're gonna check out that branch and then what we're gonna do is gonna cherry pick the commit that we just made on the master branch so that it gets added on top of the get history for this other branch that we're actually using that branch is what we want there is a linear history of every build that's run so there's gonna be a commit for every single build and we want that to be a linear history I used to have this set up so that I was using merge strategy that was creating this get history that if you visualize the get history it was an endlessly recursive branch of commits because it was actually creating merge commits and a bunch of other headaches by using cherry pick we're just grabbing that commit and we have to use a special merge strategy here otherwise it creates problems for anyone in the audience who may be an expert in get more so than myself I would love to talk after as well I actually currently have a bug where I found a work around over the last few days with this in some cases the merge strategy subtree works for this in other cases it doesn't and for those cases I end up using a recursive merge strategy with the strategy option of theirs but I think there's probably a better way to do this if you're wondering why you wouldn't do a merge or a rebase here it's because these two different branches don't have any common history because we're sort of like doing something that get isn't really set up to do it doesn't like this because we're saying we're gonna initialize repository and I'm just saying I wanna take whatever is in that build and I wanna commit it on top of another branch but they have no common history the first the new build doesn't have any history at all so I had to do a lot of back flips to get around this and then we're going to push the result once that's committed we're gonna push it to the builds repo the headless repo and then we can then at that point deploy this to our vhost if you want to have a vhost on your environment and you wanna run that build you can see now how simple the deployment process becomes because it's just a repository so we're just gonna fetch from the builds repo and reset to the latest commit on that branch so just to take a step back from the code and visualize this again this is what the flow is the builds triggered make files downloaded run the build commit the build result to the separate builds repo and then we can deploy from there and the last step of this process is undefined here but you would wanna set up something automated to trigger your builds so it might just be a nightly build that you run you may want it to pick up on pull requests that are submitted or merges or commits or whatever you wanna do for it to either pull or monitor your activity to run have that trigger builds and then also the process of this code where that code gets run and how it's organized is you know it's up to you it could be done in any different way like I mentioned this originally was a series this originally was just writing down steps that I was doing manually and I did that a few times and then I wrote down the steps in bash so that then I had scripts and lastly this could also be just commands so I've worked for about the last month on this so taking those bash scripts and converting them to actual Drush commands if this way of doing things might end up being interesting to you definitely encourage you to take a look at the work that I've been doing it could actually save you all of the effort because I know that some of this stuff probably looks a bit hairy so I created a utility called Drush Get Ops it has four commands right now this is really a proof of concept but I will tell you that these concepts in this way of structuring things is not a proof of concept so this has been employed on a number of very large scale Drupal sites successfully this also has helped with the problem of being able to architect code the way we wanted to and still be able to deploy to Pantheon and Aquia who wouldn't support running a build on their environment so you actually have to pass them your code they want that to happen through repository ideally so this actually solved that headache by saying okay let's still develop the way we want to then we can have a build process, a build repo and we can just use the builds repo for our DevOps in terms of deployment so there are four commands there's an init command, a build command those are the sort of infrastructure commands those are the steps that I just walked through all the code of and then in the working environment this is the newer work that I've been doing that's less tested is more for developers to use in a working environment whether it be local or somewhere else there's a clone command and a pull command I am going to try to be brave here we have a little bit of time and do a real demo I know that it's not a good idea but let's see how it goes and I figured it's like a reward for it being the afternoon you guys sticking around with me get to experience the suspense okay so let me see if I'm still logged in okay so let's how does that compare with me let's see I can make it a little bigger so hopefully you can see that fairly well okay so I'm on what we might call my build server right now right now I'm actually in my site right in the vhost section of my build server what I'm going to do is I'm going to run those drush commands so the first one is I'm going to run in here you can see what's in this directory it just has a logs directory and some backups and then a public directory the public directory is actually my vhost site route so I'm going to run the getopsinit command first the getopsinit command just sets up that directory structure and does that first setup step where it's creating the headless repo and the other repos so when I do that now you can look at the contents of this directory you see there's the public but there's now there's also the public build and the public builds repo directories if we look inside each one of these we'll find a get repo so you see in there we have our get a gore file that we set up and we have a get repo inside of that build directory this build directory is a throwaway anyway we're going to end up getting rid of that and replacing it every time we run a build inside of the builds repo directory you can see for those of you not familiar with the headless repo this is what it would look like the contents of the headless repo is how it's different you see just the get specific files in there and lastly in our vhost we can see the same thing it's actually going to look exact to the same as the build directory so we have our getignore and our get file alright so now what we're going to do is we're going to run this is the step that might fail due to connection everything else we're going to run the getops build command don't pay too much attention to all I'm passing a bunch of flags essentially what I'm doing is I'm going to download a the build file from get hub and I'm using a strategy that's not necessary in this case it's actually a public repo but if it were a private repo you have to use the API in order to be able to actually grab that file and that's the purpose of all this you'll also notice that I have a get hub token in here which I'm going to change immediately after this so if you can hack me somehow using that token between now and then props to you okay so that initialized the build it's actually running it's using Drushmake right now to run the build this may take a second it's just a minimal install profile so if it does start working it shouldn't take long yep yeah so the question is where is the make file wouldn't it be in the public directory isn't it part of the install profile so yes it is that's it is in my public directory in this case and it's just sitting in it's wherever you want to put it but in my case I like to put it in my install profile so yeah I'm downloading it from there just the individual file because that's all we need to initialize the build does that make sense there wasn't because that's just the initialization step in the get ops build command I'm downloading the file as part of that just from get from yeah from get hub in this case download the file from get hub dumping it into a temporary directory and then running Drushmake on that file okay so it's completed this process so it's done the full build and if we just ls we're in the public directory this is my v-host you can see Drupal core here if I look at my get history now you'll see that I have the initial commit which is part of the setup process I now have another commit that says build and then it has a timestamp that's the result of this first build that I just ran so if I go back up and I look at the public build directory which is redundant at this point because it'll roughly match what's in the other one gotcha gotcha course connection would crap out right now alright so this roughly matches what was in the v-host directory alright so that's it really for this process to work on to have the build server set up that the get ops in it is a one-time command you need to run to just set up the structure and then the build command is something that you would actually have like your Jenkins task for instance running for you whenever a build was triggered right now that command is making a lot of assumptions about how you wanna do things there are some flags and parameters you can pass it but we could add more if anyone's interested in this we can definitely make it more robust okay so I'm gonna flip back over to local and show you the other two commands so I'm just sending a directory let's say my working directory on my local site I am a themeer I come out of the project I don't have anything set up so what I'm gonna do is I'm gonna run the get ops clone command first I'm gonna end up passing it where exactly that builds repo is in terms of the remote I run that it's gonna clone that builds repo and then it's gonna do some magic stuff some really important stuff so it's gonna clone that repository but it's not just get clone otherwise it could just run get clone some of the output here is cause I'm still debugging so apologize for that but what it does is it's gonna create I gave it barefoot clone that's what I called the directory okay so what we see here is we have Drupal root if I look at hidden files you'll see there's no get repository here okay so if I did just get clone it would have pulled that down it would have clone that repository it would have been a get repo there it doesn't have one because this command is a wrapper so that I can go in and I use the same I just extend classes that are already in Drushmake to recursively search through the project files and look for any make well actually I pass it the make file but then from that make file recursively go through all the projects and I look for any projects that specify get as the download method in the make file and then what I do is I get rid of the get repo that would have been in the site root and I initialize those other repos with the appropriate remote pointing back to whatever you'd find in the make file so that's a little bit complicated to understand but I'll illustrate it here shortly okay so I now you can see here I have a repo here so my this command actually found that the install profile itself is using the get strategy for downloading a repo it goes in there it sets up that get repo and you can see now I have my install profile get repo set up for me I didn't even have to think about it importantly you can also do this for see if I still have this no so the important part is not just for the install profile but if you have other custom modules that you're building and they have their own get history it's gonna find those as well and set up those repositories so here I am in a custom module that's in this project it has its own repository here as well and it was set up for me okay so that covers initializing the project so you're the themeer you pull it down okay now let's say you're the themeer you make the changes you push you commit those changes rather than for the sake of time I won't actually do that to illustrate the full power but after you had pushed your changes to the specific project that you're working on so that might be the install profile itself but it might be a custom module a custom theme that's actually broken out in its own repository you push those changes those changes get merged and then you have a problem where your local may not be up to date with the latest state of the code base especially if you're working on a team and there's a lot of moving parts or especially if you haven't actually been in this code for a week or something it's a safe bet you wanna refresh up from upstream so the last command is running the get off get off to pull command and actually I need to make sure I'm in the right directory okay so okay so get off to pull is gonna do roughly the same thing as clone it's just gonna pull down the changes using get pull instead but it's gonna do the same stuff where it takes the repository is actually using to pull those from it actually initializes it first in the root of the site it then pulls it then deletes it it goes through recursively checks any of the individual projects and sets up the repos there so I just wanna wrap up by saying that I think that DevOps is absolutely critical to how we develop to the nature of it and I hope you think more about that and if you do I hope you come away saying where is your repos not really the right question the right question is where all of your repos because you set up a DevOps flow before you even got started developing and that's efficiently made use of reusable components without having to sacrifice on your ability to deploy your sites from one environment to another thank you so please evaluate this session if you can take the time I'm an independent contractor I am currently available for work so I'd love to have a conversation about what your needs are and if I can help with them there's contact information at the bottom there is the repository where I have this utility the Drush GitOps will your slides be on the my slides are already up on my session page so we're good there thank you we have like three minutes so if anyone has quick questions and head to the mic go ahead so I actually have a comment more than a question yeah we use this workflow with where I work which is new media we also use Vagrant for local development so using Vagrant with our Drupal recipe which is the chef recipe you can do Drushmake install profiles and it's really simple it'll do auto templating in chef for you and the second thing is I think we should propose this as a common dev flow for the community that way while onboarding people from shop to shop they understand Drushmake they start with Drushmake I mean D.O uses Drushmake you pull down commerce that's using Drushmake I think the community should accept this and adopt it as a standard dev process more than just oh yeah this shop does it too yeah well I applaud that I think that's a great suggestion and to the first I think that's awesome and I'd love to learn more about it save a lot of work any other questions